mirror of
https://github.com/esphome/esphome.git
synced 2026-10-15 10:42:52 +00:00
[image] Follow the display rotation when choosing the loop order
A rotated display swaps x and y before the frame buffer write, so the row walk strides the frame buffer there and a strided write costs more than a strided read. The loop order is now a compile time template picked from the display rotation, so both orders keep the plain loop shape. Adds a rotated case to the host benchmark.
This commit is contained in:
@@ -23,10 +23,33 @@ void Image::draw(int x, int y, display::Display *display, Color color_on, Color
|
||||
h = clipping.y2() - y;
|
||||
}
|
||||
|
||||
// Pixel data and frame buffers are row-major, so walking rows keeps both the
|
||||
// image read and the frame buffer write sequential. A rotated display swaps
|
||||
// x and y before the write, so there the columns are walked to keep the
|
||||
// write sequential; a strided write costs more than a strided read.
|
||||
const auto rotation = display->get_rotation();
|
||||
if (rotation == display::DISPLAY_ROTATION_0_DEGREES || rotation == display::DISPLAY_ROTATION_180_DEGREES) {
|
||||
this->draw_<true>(x, y, display, color_on, color_off, img_x0, img_y0, w, h);
|
||||
} else {
|
||||
this->draw_<false>(x, y, display, color_on, color_off, img_x0, img_y0, w, h);
|
||||
}
|
||||
}
|
||||
|
||||
template<bool ROWS_OUTER>
|
||||
void Image::draw_(int x, int y, display::Display *display, Color color_on, Color color_off, int img_x0, int img_y0,
|
||||
int w, int h) {
|
||||
// The outer loop runs over rows or columns; the selects fold at compile time.
|
||||
const int outer0 = ROWS_OUTER ? img_y0 : img_x0;
|
||||
const int outer_end = ROWS_OUTER ? h : w;
|
||||
const int inner0 = ROWS_OUTER ? img_x0 : img_y0;
|
||||
const int inner_end = ROWS_OUTER ? w : h;
|
||||
|
||||
switch (type_) {
|
||||
case IMAGE_TYPE_BINARY: {
|
||||
for (int img_y = img_y0; img_y < h; img_y++) {
|
||||
for (int img_x = img_x0; img_x < w; img_x++) {
|
||||
for (int outer = outer0; outer < outer_end; outer++) {
|
||||
for (int inner = inner0; inner < inner_end; inner++) {
|
||||
const int img_x = ROWS_OUTER ? inner : outer;
|
||||
const int img_y = ROWS_OUTER ? outer : inner;
|
||||
if (this->get_binary_pixel_(img_x, img_y)) {
|
||||
display->draw_pixel_at(x + img_x, y + img_y, color_on);
|
||||
} else if (!this->transparency_) {
|
||||
@@ -37,8 +60,10 @@ void Image::draw(int x, int y, display::Display *display, Color color_on, Color
|
||||
break;
|
||||
}
|
||||
case IMAGE_TYPE_GRAYSCALE:
|
||||
for (int img_y = img_y0; img_y < h; img_y++) {
|
||||
for (int img_x = img_x0; img_x < w; img_x++) {
|
||||
for (int outer = outer0; outer < outer_end; outer++) {
|
||||
for (int inner = inner0; inner < inner_end; inner++) {
|
||||
const int img_x = ROWS_OUTER ? inner : outer;
|
||||
const int img_y = ROWS_OUTER ? outer : inner;
|
||||
const uint32_t pos = (img_x + img_y * this->width_);
|
||||
const uint8_t gray = progmem_read_byte(this->data_start_ + pos);
|
||||
Color color = Color(gray, gray, gray, 0xFF);
|
||||
@@ -62,8 +87,10 @@ void Image::draw(int x, int y, display::Display *display, Color color_on, Color
|
||||
}
|
||||
break;
|
||||
case IMAGE_TYPE_RGB565:
|
||||
for (int img_y = img_y0; img_y < h; img_y++) {
|
||||
for (int img_x = img_x0; img_x < w; img_x++) {
|
||||
for (int outer = outer0; outer < outer_end; outer++) {
|
||||
for (int inner = inner0; inner < inner_end; inner++) {
|
||||
const int img_x = ROWS_OUTER ? inner : outer;
|
||||
const int img_y = ROWS_OUTER ? outer : inner;
|
||||
auto color = this->get_rgb565_pixel_(img_x, img_y);
|
||||
if (color.w >= 0x80) {
|
||||
display->draw_pixel_at(x + img_x, y + img_y, color);
|
||||
@@ -72,8 +99,10 @@ void Image::draw(int x, int y, display::Display *display, Color color_on, Color
|
||||
}
|
||||
break;
|
||||
case IMAGE_TYPE_RGB:
|
||||
for (int img_y = img_y0; img_y < h; img_y++) {
|
||||
for (int img_x = img_x0; img_x < w; img_x++) {
|
||||
for (int outer = outer0; outer < outer_end; outer++) {
|
||||
for (int inner = inner0; inner < inner_end; inner++) {
|
||||
const int img_x = ROWS_OUTER ? inner : outer;
|
||||
const int img_y = ROWS_OUTER ? outer : inner;
|
||||
auto color = this->get_rgb_pixel_(img_x, img_y);
|
||||
if (color.w >= 0x80) {
|
||||
display->draw_pixel_at(x + img_x, y + img_y, color);
|
||||
|
||||
@@ -43,6 +43,10 @@ class Image : public display::BaseImage {
|
||||
lv_image_dsc_t *get_lv_image_dsc();
|
||||
#endif
|
||||
protected:
|
||||
/// Per-pixel draw with rows (true) or columns (false) as the outer loop.
|
||||
template<bool ROWS_OUTER>
|
||||
void draw_(int x, int y, display::Display *display, Color color_on, Color color_off, int img_x0, int img_y0, int w,
|
||||
int h);
|
||||
bool get_binary_pixel_(int x, int y) const;
|
||||
Color get_rgb_pixel_(int x, int y) const;
|
||||
Color get_rgb565_pixel_(int x, int y) const;
|
||||
|
||||
@@ -41,10 +41,12 @@ static std::unique_ptr<uint8_t[]> make_pixels() {
|
||||
return data;
|
||||
}
|
||||
|
||||
static void draw_image(benchmark::State &state, ImageType type, Transparency transparency) {
|
||||
static void draw_image(benchmark::State &state, ImageType type, Transparency transparency,
|
||||
display::DisplayRotation rotation = display::DISPLAY_ROTATION_0_DEGREES) {
|
||||
auto data = make_pixels();
|
||||
Image image(data.get(), kWidth, kHeight, type, transparency);
|
||||
BenchDisplay display;
|
||||
display.set_rotation(rotation);
|
||||
|
||||
for (auto _ : state) {
|
||||
image.draw(0, 0, &display, display::COLOR_ON, display::COLOR_OFF);
|
||||
@@ -66,6 +68,11 @@ BENCHMARK(ImageDraw_RGB565);
|
||||
static void ImageDraw_RGB(benchmark::State &state) { draw_image(state, IMAGE_TYPE_RGB, TRANSPARENCY_OPAQUE); }
|
||||
BENCHMARK(ImageDraw_RGB);
|
||||
|
||||
static void ImageDraw_RGB_Rotated(benchmark::State &state) {
|
||||
draw_image(state, IMAGE_TYPE_RGB, TRANSPARENCY_OPAQUE, display::DISPLAY_ROTATION_90_DEGREES);
|
||||
}
|
||||
BENCHMARK(ImageDraw_RGB_Rotated);
|
||||
|
||||
static void ImageDraw_RGB_Alpha(benchmark::State &state) {
|
||||
draw_image(state, IMAGE_TYPE_RGB, TRANSPARENCY_ALPHA_CHANNEL);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user