mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	Display: Introduce draw_pixels_at() method for fast block display rendering (#6034)
				
					
				
			* Introduce `draw_pixels_at()` method for fast block display rendering * Add check for 18 vs 16 bit display.
This commit is contained in:
		| @@ -35,6 +35,41 @@ void HOT Display::line(int x1, int y1, int x2, int y2, Color color) { | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| void Display::draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorOrder order, | ||||
|                              ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) { | ||||
|   size_t line_stride = x_offset + w + x_pad;  // length of each source line in pixels | ||||
|   uint32_t color_value; | ||||
|   for (int y = 0; y != h; y++) { | ||||
|     size_t source_idx = (y_offset + y) * line_stride + x_offset; | ||||
|     size_t source_idx_mod; | ||||
|     for (int x = 0; x != w; x++, source_idx++) { | ||||
|       switch (bitness) { | ||||
|         default: | ||||
|           color_value = ptr[source_idx]; | ||||
|           break; | ||||
|         case COLOR_BITNESS_565: | ||||
|           source_idx_mod = source_idx * 2; | ||||
|           if (big_endian) { | ||||
|             color_value = (ptr[source_idx_mod] << 8) + ptr[source_idx_mod + 1]; | ||||
|           } else { | ||||
|             color_value = ptr[source_idx_mod] + (ptr[source_idx_mod + 1] << 8); | ||||
|           } | ||||
|           break; | ||||
|         case COLOR_BITNESS_888: | ||||
|           source_idx_mod = source_idx * 3; | ||||
|           if (big_endian) { | ||||
|             color_value = (ptr[source_idx_mod + 0] << 16) + (ptr[source_idx_mod + 1] << 8) + ptr[source_idx_mod + 2]; | ||||
|           } else { | ||||
|             color_value = ptr[source_idx_mod + 0] + (ptr[source_idx_mod + 1] << 8) + (ptr[source_idx_mod + 2] << 16); | ||||
|           } | ||||
|           break; | ||||
|       } | ||||
|       this->draw_pixel_at(x + x_start, y + y_start, ColorUtil::to_color(color_value, order, bitness)); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| void HOT Display::horizontal_line(int x, int y, int width, Color color) { | ||||
|   // Future: Could be made more efficient by manipulating buffer directly in certain rotations. | ||||
|   for (int i = x; i < x + width; i++) | ||||
|   | ||||
| @@ -8,6 +8,7 @@ | ||||
| #include "esphome/core/color.h" | ||||
| #include "esphome/core/automation.h" | ||||
| #include "esphome/core/time.h" | ||||
| #include "display_color_utils.h" | ||||
|  | ||||
| #ifdef USE_GRAPH | ||||
| #include "esphome/components/graph/graph.h" | ||||
| @@ -185,6 +186,34 @@ class Display : public PollingComponent { | ||||
|   /// Set a single pixel at the specified coordinates to the given color. | ||||
|   virtual void draw_pixel_at(int x, int y, Color color) = 0; | ||||
|  | ||||
|   /** Given an array of pixels encoded in the nominated format, draw these into the display's buffer. | ||||
|    * The naive implementation here will work in all cases, but can be overridden by sub-classes | ||||
|    * in order to optimise the procedure. | ||||
|    * The parameters describe a rectangular block of pixels, potentially within a larger buffer. | ||||
|    * | ||||
|    * \param x_start The starting destination x position | ||||
|    * \param y_start The starting destination y position | ||||
|    * \param w the width of the pixel block | ||||
|    * \param h the height of the pixel block | ||||
|    * \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 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. | ||||
|    * | ||||
|    * The length of each source buffer line (stride) will be x_offset + w + x_pad. | ||||
|    */ | ||||
|   virtual void draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorOrder order, | ||||
|                               ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad); | ||||
|  | ||||
|   /// Convenience overload for base case where the pixels are packed into the buffer with no gaps (e.g. suits LVGL.) | ||||
|   void draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorOrder order, | ||||
|                       ColorBitness bitness, bool big_endian) { | ||||
|     this->draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, 0, 0, 0); | ||||
|   } | ||||
|  | ||||
|   /// Draw a straight line from the point [x1,y1] to [x2,y2] with the given color. | ||||
|   void line(int x1, int y1, int x2, int y2, Color color = COLOR_ON); | ||||
|  | ||||
|   | ||||
| @@ -276,6 +276,35 @@ void ILI9XXXDisplay::display_() { | ||||
|   this->y_high_ = 0; | ||||
| } | ||||
|  | ||||
| // note that this bypasses the buffer and writes directly to the display. | ||||
| void ILI9XXXDisplay::draw_pixels_at(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) { | ||||
|   if (w <= 0 || h <= 0) | ||||
|     return; | ||||
|   // if color mapping or software rotation is required, hand this off to the parent implementation. This will | ||||
|   // do color conversion pixel-by-pixel into the buffer and draw it later. If this is happening the user has not | ||||
|   // configured the renderer well. | ||||
|   if (this->rotation_ != display::DISPLAY_ROTATION_0_DEGREES || bitness != display::COLOR_BITNESS_565 || !big_endian || | ||||
|       this->is_18bitdisplay_) { | ||||
|     return display::Display::draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset, | ||||
|                                             x_pad); | ||||
|   } | ||||
|   this->enable(); | ||||
|   this->set_addr_window_(x_start, y_start, x_start + w - 1, y_start + h - 1); | ||||
|   // x_ and y_offset are offsets into the source buffer, unrelated to our own offsets into the display. | ||||
|   if (x_offset == 0 && x_pad == 0 && y_offset == 0) { | ||||
|     // we could deal here with a non-zero y_offset, but if x_offset is zero, y_offset probably will be so don't bother | ||||
|     this->write_array(ptr, w * h * 2); | ||||
|   } else { | ||||
|     auto stride = x_offset + w + x_pad; | ||||
|     for (size_t y = 0; y != h; y++) { | ||||
|       this->write_array(ptr + (y + y_offset) * stride + x_offset, w * 2); | ||||
|     } | ||||
|   } | ||||
|   this->disable(); | ||||
| } | ||||
|  | ||||
| // should return the total size: return this->get_width_internal() * this->get_height_internal() * 2 // 16bit color | ||||
| // values per bit is huge | ||||
| uint32_t ILI9XXXDisplay::get_buffer_length_() { return this->get_width_internal() * this->get_height_internal(); } | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| #pragma once | ||||
| #include "esphome/components/spi/spi.h" | ||||
| #include "esphome/components/display/display_buffer.h" | ||||
| #include "esphome/components/display/display_color_utils.h" | ||||
| #include "ili9xxx_defines.h" | ||||
| #include "ili9xxx_init.h" | ||||
|  | ||||
| @@ -84,6 +85,8 @@ class ILI9XXXDisplay : public display::DisplayBuffer, | ||||
|   void setup() override; | ||||
|  | ||||
|   display::DisplayType get_display_type() override { return display::DisplayType::DISPLAY_TYPE_COLOR; } | ||||
|   void draw_pixels_at(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; | ||||
|  | ||||
|  protected: | ||||
|   void draw_absolute_pixel_internal(int x, int y, Color color) override; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user