diff --git a/esphome/components/display/display.h b/esphome/components/display/display.h index 1a45c4d6750..f17b7d86f71 100644 --- a/esphome/components/display/display.h +++ b/esphome/components/display/display.h @@ -357,7 +357,8 @@ class Display : public PollingComponent { * \param ptr A pointer to the start of the data to be copied * \param order The ordering of the colors * \param bitness Defines the number of bits and their format for each pixel - * \param big_endian True if 16 bit values are stored big-endian + * \param big_endian True if 16 bit values are stored big-endian. Ignored for 888, which is always b,g,r + * in memory for RGB order, as LVGL and ESPHome images store it. * \param x_offset The initial x-offset into the source buffer. * \param y_offset The initial y-offset into the source buffer. * \param x_pad How many pixels are in each line after the end of the pixels to be copied. diff --git a/esphome/components/display/display_color_utils.h b/esphome/components/display/display_color_utils.h index 3cf4a54999e..bd658986519 100644 --- a/esphome/components/display/display_color_utils.h +++ b/esphome/components/display/display_color_utils.h @@ -23,9 +23,8 @@ class ColorUtil { return (ptr[idx] << 8) + ptr[idx + 1]; return ptr[idx] + (ptr[idx + 1] << 8); } else if constexpr (BITNESS == COLOR_BITNESS_888) { + // Always the LVGL RGB888 layout, b,g,r in memory for RGB order; byte order applies to 565 only const size_t idx = index * 3; - if (big_endian) - return (ptr[idx + 0] << 16) + (ptr[idx + 1] << 8) + ptr[idx + 2]; return ptr[idx + 0] + (ptr[idx + 1] << 8) + (ptr[idx + 2] << 16); } else { return ptr[index]; diff --git a/esphome/components/hub75/hub75.cpp b/esphome/components/hub75/hub75.cpp index 226b59a2912..5f2149747e1 100644 --- a/esphome/components/hub75/hub75.cpp +++ b/esphome/components/hub75/hub75.cpp @@ -160,7 +160,8 @@ void HOT HUB75Display::draw_pixels_at(int x_start, int y_start, int w, int h, co // 24-bit: 3 bytes per pixel, tightly packed format = Hub75PixelFormat::RGB888; bytes_per_pixel = 3; - // Note: 24-bit is always RGB order in LVGL + // ESPHome RGB order 888 is b,g,r in memory, which hub75 calls BGR + color_order = (order == ColorOrder::COLOR_ORDER_RGB) ? Hub75ColorOrder::BGR : Hub75ColorOrder::RGB; #else ESP_LOGE(TAG, "Unsupported LV_COLOR_DEPTH: %d", LV_COLOR_DEPTH); return; @@ -169,7 +170,8 @@ void HOT HUB75Display::draw_pixels_at(int x_start, int y_start, int w, int h, co // Non-LVGL mode: standard 24-bit RGB888 format = Hub75PixelFormat::RGB888; bytes_per_pixel = 3; - color_order = (order == ColorOrder::COLOR_ORDER_RGB) ? Hub75ColorOrder::RGB : Hub75ColorOrder::BGR; + // ESPHome RGB order 888 is b,g,r in memory, which hub75 calls BGR + color_order = (order == ColorOrder::COLOR_ORDER_RGB) ? Hub75ColorOrder::BGR : Hub75ColorOrder::RGB; #endif } else { ESP_LOGE(TAG, "Unsupported bitness: %d", static_cast(bitness)); diff --git a/esphome/components/it8951/it8951.cpp b/esphome/components/it8951/it8951.cpp index 565f6f7f8bb..3612b795b98 100644 --- a/esphome/components/it8951/it8951.cpp +++ b/esphome/components/it8951/it8951.cpp @@ -987,10 +987,7 @@ void HOT IT8951Display::draw_pixels_at(int x_start, int y_start, int w, int h, c } case COLOR_BITNESS_888: { const size_t i = source_idx * 3; - color_value = - big_endian - ? (static_cast(ptr[i]) << 16) | (static_cast(ptr[i + 1]) << 8) | ptr[i + 2] - : ptr[i] | (static_cast(ptr[i + 1]) << 8) | (static_cast(ptr[i + 2]) << 16); + color_value = ptr[i] | (static_cast(ptr[i + 1]) << 8) | (static_cast(ptr[i + 2]) << 16); break; } default: diff --git a/esphome/components/mipi_dsi/mipi_dsi.cpp b/esphome/components/mipi_dsi/mipi_dsi.cpp index a27be568f25..64166012c20 100644 --- a/esphome/components/mipi_dsi/mipi_dsi.cpp +++ b/esphome/components/mipi_dsi/mipi_dsi.cpp @@ -297,15 +297,10 @@ void MipiDsi::draw_pixel_at(int x, int y, Color color) { break; } case display::COLOR_BITNESS_888: - if (this->color_mode_ == display::COLOR_ORDER_BGR) { - this->buffer_[pos * 3] = color.b; - this->buffer_[pos * 3 + 1] = color.g; - this->buffer_[pos * 3 + 2] = color.r; - } else { - this->buffer_[pos * 3] = color.r; - this->buffer_[pos * 3 + 1] = color.g; - this->buffer_[pos * 3 + 2] = color.b; - } + // The panel applies the colour order, so the buffer keeps the standard b,g,r layout + this->buffer_[pos * 3] = color.b; + this->buffer_[pos * 3 + 1] = color.g; + this->buffer_[pos * 3 + 2] = color.r; break; case display::COLOR_BITNESS_332: break; @@ -341,19 +336,12 @@ void MipiDsi::fill(Color color) { } case display::COLOR_BITNESS_888: - if (this->color_mode_ == display::COLOR_ORDER_BGR) { - for (size_t i = 0; i != this->width_ * this->height_; i++) { - this->buffer_[i * 3 + 0] = color.b; - this->buffer_[i * 3 + 1] = color.g; - this->buffer_[i * 3 + 2] = color.r; - } - } else { - for (size_t i = 0; i != this->width_ * this->height_; i++) { - this->buffer_[i * 3 + 0] = color.r; - this->buffer_[i * 3 + 1] = color.g; - this->buffer_[i * 3 + 2] = color.b; - } + for (size_t i = 0; i != this->width_ * this->height_; i++) { + this->buffer_[i * 3 + 0] = color.b; + this->buffer_[i * 3 + 1] = color.g; + this->buffer_[i * 3 + 2] = color.r; } + break; default: break; diff --git a/esphome/components/mipi_dsi/mipi_dsi.h b/esphome/components/mipi_dsi/mipi_dsi.h index 4df22354681..ba3f29ca05a 100644 --- a/esphome/components/mipi_dsi/mipi_dsi.h +++ b/esphome/components/mipi_dsi/mipi_dsi.h @@ -39,8 +39,6 @@ class MipiDsi final : public display::Display { public: MipiDsi(size_t width, size_t height, display::ColorBitness color_depth, uint8_t pixel_mode) : width_(width), height_(height), color_depth_(color_depth), pixel_mode_(pixel_mode) {} - display::ColorOrder get_color_mode() { return this->color_mode_; } - void set_color_mode(display::ColorOrder color_mode) { this->color_mode_ = color_mode; } void set_invert_colors(bool invert_colors) { this->invert_colors_ = invert_colors; } display::DisplayType get_display_type() override { return display::DisplayType::DISPLAY_TYPE_COLOR; } @@ -102,7 +100,6 @@ class MipiDsi final : public display::Display { uint8_t lanes_{2}; // 1, 2, 3 or 4 lanes bool invert_colors_{}; - display::ColorOrder color_mode_{display::COLOR_ORDER_BGR}; display::ColorBitness color_depth_; uint8_t pixel_mode_{}; diff --git a/tests/components/display/test_draw_pixels_at.cpp b/tests/components/display/test_draw_pixels_at.cpp index c8c32d15145..1278e2462df 100644 --- a/tests/components/display/test_draw_pixels_at.cpp +++ b/tests/components/display/test_draw_pixels_at.cpp @@ -62,8 +62,7 @@ static void expect_walks_match(ColorBitness bitness, int bytes_per_pixel, bool b TEST(DrawPixelsAt, ColumnWalkMatchesRowWalk332) { expect_walks_match(COLOR_BITNESS_332, 1, true); } TEST(DrawPixelsAt, ColumnWalkMatchesRowWalk565BigEndian) { expect_walks_match(COLOR_BITNESS_565, 2, true); } TEST(DrawPixelsAt, ColumnWalkMatchesRowWalk565LittleEndian) { expect_walks_match(COLOR_BITNESS_565, 2, false); } -TEST(DrawPixelsAt, ColumnWalkMatchesRowWalk888BigEndian) { expect_walks_match(COLOR_BITNESS_888, 3, true); } -TEST(DrawPixelsAt, ColumnWalkMatchesRowWalk888LittleEndian) { expect_walks_match(COLOR_BITNESS_888, 3, false); } +TEST(DrawPixelsAt, ColumnWalkMatchesRowWalk888) { expect_walks_match(COLOR_BITNESS_888, 3, false); } // One known pixel per bitness and byte order, so a decode that swapped bytes or channels // could not pass the walk comparison above by being wrong the same way twice. @@ -81,8 +80,9 @@ TEST(DrawPixelsAt, Golden565BigEndian) { TEST(DrawPixelsAt, Golden565LittleEndian) { expect_golden(COLOR_BITNESS_565, {0xE0, 0x07}, false, Color(0, 255, 0)); // 0x07E0: pure green } -TEST(DrawPixelsAt, Golden888BigEndian) { - expect_golden(COLOR_BITNESS_888, {0x10, 0x20, 0x30}, true, Color(0x10, 0x20, 0x30)); +// 888 is always b,g,r in memory for RGB order, whatever the byte order flag says +TEST(DrawPixelsAt, Golden888IgnoresBigEndian) { + expect_golden(COLOR_BITNESS_888, {0x10, 0x20, 0x30}, true, Color(0x30, 0x20, 0x10)); } TEST(DrawPixelsAt, Golden888LittleEndian) { expect_golden(COLOR_BITNESS_888, {0x10, 0x20, 0x30}, false, Color(0x30, 0x20, 0x10));