roo_display
API Documentation for roo_display
Loading...
Searching...
No Matches
addr_window_device.h
Go to the documentation of this file.
1#pragma once
2
3#include <type_traits>
4
5#include "compactor.h"
12#include "roo_io/data/byte_order.h"
13
14namespace roo_display {
15
16// Convenience foundational driver for display devices that use the common
17// concept of 'address window'. Virtually all SPI devices, including various ILI
18// and ST devices, belong in this category. This class implements the entire
19// contract of a display device, providing an optimized implementation for pixel
20// write, using a Compactor class that detects writes to adjacent pixels and
21// minimizes the number of address window commands.
22//
23// To implement a driver for a particular device on the basis of this class, you
24// need to provide an implementation of the 'Target' class, with the following
25// template contract:
26//
27// class Target {
28// public:
29// typedef ColorMode;
30// static constexpr ByteOrder byte_order;
31// Target();
32// Target(Target&&);
33// Target(int16_t width, int16_t height);
34// int16_t width() const;
35// int16_t height() const;
36// void init();
37// void begin();
38// void end();
39// void setOrientation(Orientation);
40// void setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);
41// void startRamWrite();
42// void flush();
43// void ramWrite(const roo::byte* data, size_t pixel_count);
44// void ramFill(const roo::byte* data, size_t pixel_count);
45//};
46//
47// See ili9341.h for a specific example.
48//
49// Many display devices rely on the same underying hardware contract, assumimg
50// that the display is connected to some kind of shared bus (e.g. SPI), and that
51// it has dedicated pins for 'chip select' (CS), 'data / command' (DC), and
52// optionally reset (RST). If your device fits this description, you can use
53// TransportBus (see transport_bus.h) to implement the Target.
54template <typename Target>
56 public:
57 using ColorMode = typename Target::ColorMode;
59 static constexpr ByteOrder byte_order = Target::byte_order;
60 static constexpr int kBytesPerPixel =
62 using raw_color_type = roo::byte[kBytesPerPixel];
63
66
68 : AddrWindowDevice(Target(width, height)) {}
69
72
73 template <typename... Args>
75 : AddrWindowDevice(Orientation::Default(),
76 Target(std::forward<Args>(args)...)) {}
77
78 template <typename... Args>
81
83 : DisplayDevice(orientation, target.width(), target.height()),
84 target_(std::move(target)),
86 bgcolor_(0xFF7F7F7F),
87 compactor_() {}
88
89 ~AddrWindowDevice() override {}
90
91 void init() override {
92 target_.init();
93 initialized_ = true;
94 target_.begin();
95 target_.setOrientation(orientation());
96 target_.end();
97 }
98
99 void begin() override { target_.begin(); }
100
101 void end() override { target_.end(); }
102
103 void setBgColorHint(Color bgcolor) override { bgcolor_ = bgcolor; }
104
106 BlendingMode mode) override {
107 target_.setAddrWindow(x0, y0, x1, y1);
108 target_.startRamWrite();
109 blending_mode_ = mode;
110 }
111
112 void write(Color* color, uint32_t pixel_count) override {
113 roo::byte buffer[64 * kBytesPerPixel];
116 if (remainder > 0) {
117 processColorSequence(blending_mode_, color, buffer, remainder);
118 target_.ramWrite(buffer, remainder);
119 color += remainder;
120 }
121 while (chunks-- > 0) {
122 processColorSequence(blending_mode_, color, buffer, 64);
123 target_.ramWrite(buffer, 64);
124 color += 64;
125 }
126 }
127
128 void fill(Color color, uint32_t pixel_count) override {
130 processColor(blending_mode_, color, raw_color);
131 target_.ramFill(raw_color, pixel_count);
132 }
133
135 int16_t* y0, int16_t* x1, int16_t* y1,
136 uint16_t count) override {
138 while (count-- > 0) {
139 target_.setAddrWindow(*x0, *y0, *x1, *y1);
140 target_.startRamWrite();
141 uint32_t pixel_count = (*x1 - *x0 + 1) * (*y1 - *y0 + 1);
142 x0++;
143 y0++;
144 x1++;
145 y1++;
146 Color mycolor = *color++;
147 processColor(blending_mode, mycolor, raw_color);
148 target_.ramFill(raw_color, pixel_count);
149 }
150 }
151
153 int16_t* y0, int16_t* x1, int16_t* y1,
154 uint16_t count) override {
156 processColor(blending_mode, color, raw_color);
157 while (count-- > 0) {
158 target_.setAddrWindow(*x0, *y0, *x1, *y1);
159 target_.startRamWrite();
160 uint32_t pixel_count = (*x1 - *x0 + 1) * (*y1 - *y0 + 1);
161 x0++;
162 y0++;
163 x1++;
164 y1++;
165 target_.ramFill(raw_color, pixel_count);
166 }
167 }
168
170 uint16_t pixel_count) override {
171 blending_mode_ = mode;
172 compactor_.drawPixels(
173 xs, ys, pixel_count,
174 [this, mode, colors](int16_t offset, int16_t x, int16_t y,
176 int16_t count) {
177 switch (direction) {
178 case Compactor::RIGHT: {
179 target_.setAddrWindow(x, y, x + count - 1, y);
180 break;
181 }
182 case Compactor::DOWN: {
183 target_.setAddrWindow(x, y, x, y + count - 1);
184 break;
185 }
186 case Compactor::LEFT: {
187 target_.setAddrWindow(x - count + 1, y, x, y);
188 std::reverse(colors + offset, colors + offset + count);
189 break;
190 }
191 case Compactor::UP: {
192 target_.setAddrWindow(x, y - count + 1, x, y);
193 std::reverse(colors + offset, colors + offset + count);
194 break;
195 }
196 }
197 target_.startRamWrite();
198 AddrWindowDevice::write(colors + offset, count);
199 });
200 }
201
203 int16_t* ys, uint16_t pixel_count) override {
205 processColor(blending_mode, color, raw_color);
206 const roo::byte* raw_color_ptr = raw_color;
207 compactor_.drawPixels(
208 xs, ys, pixel_count,
209 [this, raw_color_ptr](int16_t offset, int16_t x, int16_t y,
211 int16_t count) {
212 switch (direction) {
213 case Compactor::RIGHT: {
214 target_.setAddrWindow(x, y, x + count - 1, y);
215 break;
216 }
217 case Compactor::DOWN: {
218 target_.setAddrWindow(x, y, x, y + count - 1);
219 break;
220 }
221 case Compactor::LEFT: {
222 target_.setAddrWindow(x - count + 1, y, x, y);
223 break;
224 }
225 case Compactor::UP: {
226 target_.setAddrWindow(x, y - count + 1, x, y);
227 break;
228 }
229 }
230 target_.startRamWrite();
231 target_.ramFill(raw_color_ptr, count);
232 });
233 }
234
235 const ColorFormat& getColorFormat() const override {
236 static const internal::ColorFormatImpl<typename Target::ColorMode,
237 Target::byte_order,
239 format(color_mode());
240 return format;
241 }
242
243 const ColorMode& color_mode() const {
244 static const ColorMode mode;
245 return mode;
246 }
247
248 void drawDirectRect(const roo::byte* data, size_t row_width_bytes,
251 if (src_x1 < src_x0 || src_y1 < src_y0) return;
253 1) {
256 return;
257 }
258
259 int16_t width = src_x1 - src_x0 + 1;
260 int16_t height = src_y1 - src_y0 + 1;
261 target_.setAddrWindow(dst_x0, dst_y0, dst_x0 + width - 1,
262 dst_y0 + height - 1);
263 const size_t width_bytes = static_cast<size_t>(width) * kBytesPerPixel;
264 const roo::byte* row = data +
265 static_cast<size_t>(src_y0) * row_width_bytes +
266 static_cast<size_t>(src_x0) * kBytesPerPixel;
267 target_.startRamWrite();
268
269 if (row_width_bytes == width_bytes) {
270 target_.ramWrite(row, static_cast<size_t>(width) * height);
271 return;
272 }
273
274 for (int16_t y = 0; y < height; ++y) {
275 target_.ramWrite(row, width);
277 }
278 }
279
280 void drawDirectRectAsync(const roo::byte* data, size_t row_width_bytes,
283 int16_t dst_y0) override {
284 drawDirectRectAsyncImpl(data, row_width_bytes, src_x0, src_y0, src_x1,
286 }
287
288 void flush() override { target_.flush(); }
289
290 void orientationUpdated() override {
291 if (!initialized_) {
292 // Initialization will set the orientation.
293 return;
294 }
295 target_.setOrientation(orientation());
296 }
297
298 protected:
301
302 private:
303 // Compile-time capability probe: true when Target exposes
304 // ramWriteAsyncBlit(const roo::byte*, size_t, size_t, size_t).
305 // Used to select async drawDirectRectAsync implementation without runtime
306 // branching.
307 template <typename U, typename = void>
308 struct has_async_blit : std::false_type {};
309
310 template <typename U>
311 struct has_async_blit<
312 U, std::void_t<decltype(std::declval<U&>().ramWriteAsyncBlit(
313 std::declval<const roo::byte*>(), std::declval<size_t>(),
314 std::declval<size_t>(), std::declval<size_t>()))>>
315 : std::true_type {};
316
317 // Async path selected when has_async_blit<Target>::value == true.
318 void drawDirectRectAsyncImpl(const roo::byte* data, size_t row_width_bytes,
319 int16_t src_x0, int16_t src_y0, int16_t src_x1,
320 int16_t src_y1, int16_t dst_x0, int16_t dst_y0,
321 std::true_type /*has_async*/) {
322 if (src_x1 < src_x0 || src_y1 < src_y0) {
323 return;
324 }
325
326 if constexpr (ColorTraits<typename Target::ColorMode>::bytes_per_pixel <
327 1) {
328 drawDirectRect(data, row_width_bytes, src_x0, src_y0, src_x1, src_y1,
329 dst_x0, dst_y0);
330 return;
331 }
332
333 int16_t width = src_x1 - src_x0 + 1;
334 int16_t height = src_y1 - src_y0 + 1;
335 target_.setAddrWindow(dst_x0, dst_y0, dst_x0 + width - 1,
336 dst_y0 + height - 1);
337 target_.startRamWrite();
338
339 const size_t width_bytes = static_cast<size_t>(width) * kBytesPerPixel;
340 const roo::byte* row = data +
341 static_cast<size_t>(src_y0) * row_width_bytes +
342 static_cast<size_t>(src_x0) * kBytesPerPixel;
343 target_.ramWriteAsyncBlit(row, row_width_bytes, width_bytes,
344 static_cast<size_t>(height));
345 }
346
347 // Synchronous fallback selected when Target has no async blit API.
348 void drawDirectRectAsyncImpl(const roo::byte* data, size_t row_width_bytes,
349 int16_t src_x0, int16_t src_y0, int16_t src_x1,
350 int16_t src_y1, int16_t dst_x0, int16_t dst_y0,
351 std::false_type /*has_async*/) {
352 drawDirectRect(data, row_width_bytes, src_x0, src_y0, src_x1, src_y1,
353 dst_x0, dst_y0);
354 }
355
356 void processColor(BlendingMode blending_mode, Color src, roo::byte* dest)
357 __attribute__((always_inline)) {
358 src = ApplyBlending(blending_mode, bgcolor_, src);
359 ColorIo<typename Target::ColorMode, Target::byte_order> io;
360 io.store(src, dest);
361 }
362
363 void processColorSequence(BlendingMode blending_mode, Color* src,
364 roo::byte* dest, uint32_t pixel_count)
365 __attribute__((always_inline)) {
366 ApplyBlendingOverBackground(blending_mode, bgcolor_, src, pixel_count);
367 ColorIo<typename Target::ColorMode, Target::byte_order> io;
368 while (pixel_count-- > 0) {
369 io.store(*src++, dest);
370 dest += kBytesPerPixel;
371 }
372 }
373
374 Color bgcolor_;
375 uint16_t last_x0_, last_x1_, last_y0_, last_y1_;
376 // Set by setAddress and used by write().
377 BlendingMode blending_mode_;
378 Compactor compactor_;
379};
380
381} // namespace roo_display
const ColorMode & color_mode() const
void flush() override
Wait until pending asynchronous drawing operations complete.
void writePixels(BlendingMode mode, Color *colors, int16_t *xs, int16_t *ys, uint16_t pixel_count) override
Draw the specified pixels (per-pixel colors). Invalidates the address window.
typename Target::ColorMode ColorMode
void end() override
Finalize the previously entered write transaction, flushing any pending writes.
void fill(Color color, uint32_t pixel_count) override
Write pixel_count copies of the same color into the current address window.
void init() override
Initialize the display driver.
void writeRects(BlendingMode blending_mode, Color *color, int16_t *x0, int16_t *y0, int16_t *x1, int16_t *y1, uint16_t count) override
Draw the specified rectangles (per-rectangle colors). Invalidates the address window.
void drawDirectRect(const roo::byte *data, size_t row_width_bytes, int16_t src_x0, int16_t src_y0, int16_t src_x1, int16_t src_y1, int16_t dst_x0, int16_t dst_y0) override
Draw a rectangle represented in the device's native color format.
void begin() override
Enter a write transaction.
AddrWindowDevice(Orientation orientation, Target target)
void orientationUpdated() override
Invoked when orientation() is updated.
void write(Color *color, uint32_t pixel_count) override
Write pixels into the current address window.
void fillPixels(BlendingMode blending_mode, Color color, int16_t *xs, int16_t *ys, uint16_t pixel_count) override
Draw the specified pixels using the same color. Invalidates the address window.
AddrWindowDevice(uint16_t width, uint16_t height)
void setAddress(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, BlendingMode mode) override
Set a rectangular window filled by subsequent calls to write().
static constexpr ByteOrder byte_order
AddrWindowDevice(Orientation orientation, Args &&... args)
void setBgColorHint(Color bgcolor) override
Provide a background color hint for source-over blending.
void drawDirectRectAsync(const roo::byte *data, size_t row_width_bytes, int16_t src_x0, int16_t src_y0, int16_t src_x1, int16_t src_y1, int16_t dst_x0, int16_t dst_y0) override
Asynchronous variant of drawDirectRect().
void fillRects(BlendingMode blending_mode, Color color, int16_t *x0, int16_t *y0, int16_t *x1, int16_t *y1, uint16_t count) override
Draw the specified rectangles using the same color. Invalidates the address window.
AddrWindowDevice(Orientation orientation, uint16_t width, uint16_t height)
static constexpr int kBytesPerPixel
static constexpr ColorPixelOrder pixel_order
roo::byte[kBytesPerPixel] raw_color_type
const ColorFormat & getColorFormat() const override
Return the native color format used by this device for direct drawing.
ARGB8888 color stored as a 32-bit unsigned integer.
Definition color.h:16
void drawPixels(int16_t *xs, int16_t *ys, uint16_t pixel_count, Writer write=Writer())
Definition compactor.h:26
Base class for display device drivers.
Definition device.h:223
Orientation orientation() const
Return the current orientation of the display.
Definition device.h:250
virtual void drawDirectRect(const roo::byte *data, size_t row_width_bytes, int16_t src_x0, int16_t src_y0, int16_t src_x1, int16_t src_y1, int16_t dst_x0, int16_t dst_y0)
Draw a rectangle represented in the device's native color format.
Definition device.cpp:33
Represents the orientation of a display device.
Definition orientation.h:25
Defines 140 opaque HTML named colors.
void ApplyBlendingOverBackground(BlendingMode mode, Color bg, Color *src, int16_t count)
Definition blending.h:588
BlendingMode
Porter-Duff style blending modes.
Definition blending.h:17
Color ApplyBlending(BlendingMode mode, Color dst, Color src)
Definition blending.h:554
roo_io::ByteOrder ByteOrder
Definition byte_order.h:7
Color bgcolor
Definition smooth.cpp:889
BlendingMode blending_mode
Definition smooth.cpp:888
Traits for a color mode's storage characteristics.
Definition traits.h:9