roo_display
API Documentation for roo_display
Loading...
Searching...
No Matches
esp32s3_dma_parallel_rgb565.h
Go to the documentation of this file.
1#pragma once
2
4
5#if !defined(ESP_PLATFORM) || !(CONFIG_IDF_TARGET_ESP32S3)
6#warning Compilation target must be ESP32_S3 for this device.
7#else
8
9#include <memory>
10
11#include "rom/cache.h"
18
19namespace roo_display {
20
21namespace internal {
22
23class Rgb565Dma : public Rgb565 {};
24
25template <>
26struct ColorFormatTraits<Rgb565Dma> {
27 static constexpr const DisplayOutput::ColorFormat::Mode mode =
29};
30
31} // namespace internal
32
33template <roo_io::ByteOrder byte_order>
34struct RawFullByteBlender<internal::Rgb565Dma, BlendingMode::kSourceOver,
35 byte_order> {
36 inline void operator()(roo::byte *dst, Color src,
37 const internal::Rgb565Dma &mode) const {
38 ColorIo<internal::Rgb565Dma, byte_order> io;
39 io.store(AlphaBlendOverOpaque(io.load(dst, mode), src), dst, mode);
40 }
41};
42
43namespace internal {
44
45template <BlendingMode blending_mode>
46class Rgb565DmaBlendingWriterOperator {
47 public:
48 Rgb565DmaBlendingWriterOperator(Rgb565Dma color_mode, const Color *color)
49 : color_mode_(color_mode), color_(color) {}
50
51 void operator()(roo::byte *p, uint32_t offset) {
52 constexpr uint32_t kBytesPerPixel = ColorTraits<Rgb565Dma>::bytes_per_pixel;
53 roo::byte *cursor = p + offset * kBytesPerPixel;
54 RawFullByteBlender<Rgb565Dma, blending_mode, roo_io::kLittleEndian> blender;
55 blender(cursor, *color_++, color_mode_);
56 Cache_WriteBack_Addr((uint32_t)(p) + offset * kBytesPerPixel,
57 kBytesPerPixel);
58 }
59
60 void operator()(roo::byte *p, uint32_t offset, uint32_t count) {
61 constexpr uint32_t kBytesPerPixel = ColorTraits<Rgb565Dma>::bytes_per_pixel;
62 roo::byte *cursor = p + offset * kBytesPerPixel;
63 RawFullByteBlender<Rgb565Dma, blending_mode, roo_io::kLittleEndian> blender;
64 uint32_t orig_count = count;
65 while (count-- > 0) {
66 blender(cursor, *color_++, color_mode_);
67 cursor += kBytesPerPixel;
68 }
69 Cache_WriteBack_Addr((uint32_t)(p) + offset * kBytesPerPixel,
70 orig_count * kBytesPerPixel);
71 }
72
73 private:
74 Rgb565Dma color_mode_;
75 const Color *color_;
76};
77
78template <>
79struct BlendingWriter<Rgb565Dma, ColorPixelOrder::kMsbFirst,
80 roo_io::kLittleEndian> {
81 template <BlendingMode blending_mode>
82 using Operator = Rgb565DmaBlendingWriterOperator<blending_mode>;
83};
84
85template <>
86class GenericWriter<Rgb565Dma, ColorPixelOrder::kMsbFirst,
87 roo_io::kLittleEndian, 1, uint16_t> {
88 public:
89 GenericWriter(const Rgb565Dma &color_mode, BlendingMode blending_mode,
90 Color *color)
91 : color_(color), blending_mode_(blending_mode) {}
92
93 void operator()(roo::byte *p, uint32_t offset) {
94 constexpr uint32_t kBytesPerPixel = ColorTraits<Rgb565Dma>::bytes_per_pixel;
95 roo::byte *cursor = p + offset * kBytesPerPixel;
96 ApplyRawFullByteBlending<Rgb565Dma, roo_io::kLittleEndian>(
97 blending_mode_, cursor, *color_++, Rgb565Dma());
98 Cache_WriteBack_Addr((uint32_t)(p) + offset * kBytesPerPixel,
99 kBytesPerPixel);
100 }
101
102 void operator()(roo::byte *p, uint32_t offset, uint32_t count) {
103 constexpr uint32_t kBytesPerPixel = ColorTraits<Rgb565Dma>::bytes_per_pixel;
104 roo::byte *cursor = p + offset * kBytesPerPixel;
105 uint32_t orig_count = count;
106 while (count-- > 0) {
107 ApplyRawFullByteBlending<Rgb565Dma, roo_io::kLittleEndian>(
108 blending_mode_, cursor, *color_++, Rgb565Dma());
109 cursor += kBytesPerPixel;
110 }
111 Cache_WriteBack_Addr((uint32_t)(p) + offset * kBytesPerPixel,
112 orig_count * kBytesPerPixel);
113 }
114
115 private:
116 Color *color_;
117 BlendingMode blending_mode_;
118};
119
120template <BlendingMode blending_mode>
121class Rgb565DmaBlendingFillerOperator {
122 public:
123 Rgb565DmaBlendingFillerOperator(Rgb565Dma color_mode, Color color)
124 : color_(color) {}
125
126 void operator()(roo::byte *p, uint32_t offset) const {
127 constexpr uint32_t kBytesPerPixel = ColorTraits<Rgb565Dma>::bytes_per_pixel;
128 roo::byte *cursor = p + offset * kBytesPerPixel;
129 RawFullByteBlender<Rgb565Dma, blending_mode, roo_io::kLittleEndian> blender;
130 blender(cursor, color_, Rgb565Dma());
131 Cache_WriteBack_Addr((uint32_t)(p) + offset * kBytesPerPixel,
132 kBytesPerPixel);
133 }
134
135 void operator()(roo::byte *p, uint32_t offset, uint32_t count) const {
136 constexpr uint32_t kBytesPerPixel = ColorTraits<Rgb565Dma>::bytes_per_pixel;
137 roo::byte *cursor = p + offset * kBytesPerPixel;
138 RawFullByteBlender<Rgb565Dma, blending_mode, roo_io::kLittleEndian> blender;
139 uint32_t orig_count = count;
140 while (count-- > 0) {
141 blender(cursor, color_, Rgb565Dma());
142 cursor += kBytesPerPixel;
143 }
144 Cache_WriteBack_Addr((uint32_t)(p) + offset * kBytesPerPixel,
145 orig_count * kBytesPerPixel);
146 }
147
148 private:
149 Color color_;
150 BlendingMode blending_mode_;
151};
152
153template <>
154struct BlendingFiller<Rgb565Dma, ColorPixelOrder::kMsbFirst,
155 roo_io::kLittleEndian> {
156 template <BlendingMode blending_mode>
157 using Operator = Rgb565DmaBlendingFillerOperator<blending_mode>;
158};
159
160template <>
161class GenericFiller<Rgb565Dma, ColorPixelOrder::kMsbFirst,
162 roo_io::kLittleEndian, 1, uint16_t> {
163 public:
164 GenericFiller(const Rgb565Dma &color_mode, BlendingMode blending_mode,
165 Color color)
166 : color_(color), blending_mode_(blending_mode) {}
167
168 void operator()(roo::byte *p, uint32_t offset) const {
169 constexpr uint32_t kBytesPerPixel = ColorTraits<Rgb565Dma>::bytes_per_pixel;
170 roo::byte *cursor = p + offset * kBytesPerPixel;
171 ApplyRawFullByteBlending<Rgb565Dma, roo_io::kLittleEndian>(
172 blending_mode_, cursor, color_, Rgb565Dma());
173 Cache_WriteBack_Addr((uint32_t)(p) + offset * kBytesPerPixel,
174 kBytesPerPixel);
175 }
176
177 void operator()(roo::byte *p, uint32_t offset, uint32_t count) const {
178 constexpr uint32_t kBytesPerPixel = ColorTraits<Rgb565Dma>::bytes_per_pixel;
179 roo::byte *cursor = p + offset * kBytesPerPixel;
180 uint32_t orig_count = count;
181 while (count-- > 0) {
182 ApplyRawFullByteBlending<Rgb565Dma, roo_io::kLittleEndian>(
183 blending_mode_, cursor, color_, Rgb565Dma());
184 cursor += kBytesPerPixel;
185 }
186 Cache_WriteBack_Addr((uint32_t)(p) + offset * kBytesPerPixel,
187 orig_count * kBytesPerPixel);
188 }
189
190 private:
191 Color color_;
192 BlendingMode blending_mode_;
193};
194
195} // namespace internal
196
197// Note: this one is mainly for performance tests and it doesn't support screen
198// rotation or alpha-blending.
199// #define FLUSH_MODE_HARDCODED
200
201namespace esp32s3_dma {
202
203enum FlushMode {
204 // Writes back after every memory write. Slow.
205 FLUSH_MODE_AGGRESSIVE = 0,
206
207 // Writes back after every driver call, i.e. per some number of pixels or
208 // rectangles.
209 FLUSH_MODE_BUFFERED = 1,
210
211 // Only writes back at the end of transaction (in device.end()). In theory,
212 // that sounds like good
213 // idea. And indeed, it seems the fastest. In practice, for some reason it
214 // causes displays to lose synchronization quite a lot.
215 FLUSH_MODE_LAZY = 2,
216};
217
218namespace internal {
219
220template <FlushMode>
221struct Traits {
222 using ColorMode = Rgb565;
223};
224
225template <>
226struct Traits<FLUSH_MODE_AGGRESSIVE> {
227 using ColorMode = ::roo_display::internal::Rgb565Dma;
228};
229
230} // namespace internal
231
232struct Config {
233 uint16_t width;
234 uint16_t height;
235 int8_t de;
236 int8_t hsync;
237 int8_t vsync;
238 int8_t pclk;
239 uint16_t hsync_pulse_width;
240 uint16_t hsync_back_porch;
241 uint16_t hsync_front_porch;
242 uint16_t hsync_polarity;
243 uint16_t vsync_pulse_width;
244 uint16_t vsync_back_porch;
245 uint16_t vsync_front_porch;
246 uint16_t vsync_polarity;
247 uint16_t pclk_active_neg;
248 int32_t prefer_speed;
249
250 int8_t r0;
251 int8_t r1;
252 int8_t r2;
253 int8_t r3;
254 int8_t r4;
255 int8_t g0;
256 int8_t g1;
257 int8_t g2;
258 int8_t g3;
259 int8_t g4;
260 int8_t g5;
261 int8_t b0;
262 int8_t b1;
263 int8_t b2;
264 int8_t b3;
265 int8_t b4;
266 bool bswap;
267};
268
269roo::byte *AllocateBuffer(const Config &config);
270
271template <FlushMode flush_mode>
272class ParallelRgb565 : public DisplayDevice {
273 public:
274 using ColorMode = Rgb565;
275 static constexpr ColorPixelOrder pixel_order = ColorPixelOrder::kMsbFirst;
276 static constexpr ByteOrder byte_order = roo_io::kLittleEndian;
277
278 ParallelRgb565(Config cfg)
279 : DisplayDevice(cfg.width, cfg.height), cfg_(std::move(cfg)) {}
280
281 void init() override;
282
283 void begin() override {}
284
285 void end() override;
286
287 void setAddress(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1,
288 BlendingMode mode) override {
289 buffer_->setAddress(x0, y0, x1, y1, mode);
290 }
291
292 void write(Color *color, uint32_t pixel_count) override;
293
294 void fill(Color color, uint32_t pixel_count) override;
295
296 void writePixels(BlendingMode mode, Color *color, int16_t *x, int16_t *y,
297 uint16_t pixel_count) override;
298
299 void fillPixels(BlendingMode mode, Color color, int16_t *x, int16_t *y,
300 uint16_t pixel_count) override;
301
302 void writeRects(BlendingMode mode, Color *color, int16_t *x0, int16_t *y0,
303 int16_t *x1, int16_t *y1, uint16_t count) override;
304
305 void fillRects(BlendingMode mode, Color color, int16_t *x0, int16_t *y0,
306 int16_t *x1, int16_t *y1, uint16_t count) override;
307
308 void drawDirectRect(const roo::byte *data, size_t row_width_bytes,
309 int16_t src_x0, int16_t src_y0, int16_t src_x1,
310 int16_t src_y1, int16_t dst_x0, int16_t dst_y0) override;
311
312 void drawDirectRectAsync(const roo::byte *data, size_t row_width_bytes,
313 int16_t src_x0, int16_t src_y0, int16_t src_x1,
314 int16_t src_y1, int16_t dst_x0,
315 int16_t dst_y0) override;
316
317 const ColorFormat &getColorFormat() const override {
318 static const ::roo_display::internal::ColorFormatImpl<
319 Rgb565, roo_io::kLittleEndian, ColorPixelOrder::kMsbFirst>
320 format(color_mode());
321 return format;
322 }
323
324 const Rgb565 &color_mode() const {
325 static const Rgb565 mode;
326 return mode;
327 }
328
329 void orientationUpdated() override {
330 if (buffer_ != nullptr) {
331 buffer_->setOrientation(orientation());
332 }
333 }
334
335 void flush() override {
336 if (buffer_ != nullptr) {
337 buffer_->flush();
338 }
339 flushCache();
340 }
341
342 private:
343 inline void flushCache() {
344 uint32_t begin = (uint32_t)buffer_->buffer();
345 uint32_t size = cfg_.width * cfg_.height * 2;
346 Cache_WriteBack_Addr(begin, size);
347 }
348
349 using Dev =
350 OffscreenDevice<typename internal::Traits<flush_mode>::ColorMode,
351 ColorPixelOrder::kMsbFirst, roo_io::kLittleEndian>;
352
353 Config cfg_;
354 std::unique_ptr<Dev> buffer_;
355};
356
357using ParallelRgb565Buffered = ParallelRgb565<FLUSH_MODE_BUFFERED>;
358
359} // namespace esp32s3_dma
360
361} // namespace roo_display
362
363#endif // #if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3)
void operator()(roo::byte *p, uint32_t offset)
Definition offscreen.h:1158
GenericFiller(ColorMode &color_mode, BlendingMode blending_mode, Color color)
Definition offscreen.h:1155
void operator()(roo::byte *p, uint32_t offset)
Definition offscreen.h:889
GenericWriter(ColorMode &color_mode, BlendingMode blending_mode, Color *color)
Definition offscreen.h:886
Defines 140 opaque HTML named colors.
BlendingMode
Porter-Duff style blending modes.
Definition blending.h:17
@ kSourceOver
Source is placed (alpha-blended) over the destination. This is the default blending mode.
Color AlphaBlendOverOpaque(Color bgc, Color fgc)
Definition blending.h:465
roo_io::ByteOrder ByteOrder
Definition byte_order.h:7
BlendingMode blending_mode
Definition smooth.cpp:888
void operator()(roo::byte *dst, Color src, const ColorMode &mode) const
Definition blending.h:605
BlendingFillerOperator< ColorMode, pixel_order, byte_order, blending_mode > Operator
Definition offscreen.h:1142
BlendingWriterOperator< ColorMode, pixel_order, byte_order, blending_mode > Operator
Definition offscreen.h:803
static constexpr const DisplayOutput::ColorFormat::Mode mode