roo_display
API Documentation for roo_display
Loading...
Searching...
No Matches
buffered_addr_window_device.h
Go to the documentation of this file.
1#pragma once
2
3#include <memory>
4
5#include "roo_backport.h"
6#include "roo_backport/byte.h"
10
11namespace roo_display {
12
13template <typename Target>
15 public:
16 using ColorMode = typename Target::ColorMode;
18 static constexpr ByteOrder byte_order = Target::byte_order;
20
23 : DisplayDevice(orientation, target.width(), target.height()),
24 target_(std::move(target)),
25 buffer_(new roo::byte[(Target::ColorMode::bits_per_pixel *
26 target.width() * target.height() +
27 7) /
28 8]),
29 buffer_dev_(target_.width(), target_.height(), buffer_.get(),
31 buffer_raster_(buffer_dev_.raster()),
32 compactor_() {}
33
35
36 void init() override { target_.init(); }
37
38 void begin() override { target_.begin(); }
39
40 void end() override {
41 flushRectCache();
42 target_.end();
43 }
44
46 BlendingMode mode) override {
47 flushRectCache();
48 buffer_dev_.setAddress(x0, y0, x1, y1, mode);
49 rect_cache_.setWindow(x0, y0, x1, y1);
50 }
51
52 void write(Color* color, uint32_t pixel_count) override {
53 buffer_dev_.write(color, pixel_count);
54 rect_cache_.pixelsWritten(pixel_count);
55 }
56
57 void fill(Color color, uint32_t pixel_count) override {
58 buffer_dev_.fill(color, pixel_count);
59 rect_cache_.pixelsWritten(pixel_count);
60 }
61
62 void writeRects(BlendingMode mode, Color* color, int16_t* x0, int16_t* y0,
63 int16_t* x1, int16_t* y1, uint16_t count) override {
64 flushRectCache();
65 buffer_dev_.writeRects(mode, color, x0, y0, x1, y1, count);
66 while (count-- > 0) {
67 target_.flushRect(buffer_raster_, *x0++, *y0++, *x1++, *y1++);
68 }
69 }
70
71 void fillRects(BlendingMode mode, Color color, int16_t* x0, int16_t* y0,
72 int16_t* x1, int16_t* y1, uint16_t count) override {
73 flushRectCache();
74 buffer_dev_.fillRects(mode, color, x0, y0, x1, y1, count);
75 while (count-- > 0) {
76 target_.flushRect(buffer_raster_, *x0++, *y0++, *x1++, *y1++);
77 }
78 }
79
80 void drawDirectRect(const roo::byte* data, size_t row_width_bytes,
83 if (src_x1 < src_x0 || src_y1 < src_y0) return;
84 flushRectCache();
87 int16_t width = src_x1 - src_x0 + 1;
88 int16_t height = src_y1 - src_y0 + 1;
89 target_.flushRect(buffer_raster_, dst_x0, dst_y0, dst_x0 + width - 1,
90 dst_y0 + height - 1);
91 }
92
94 uint16_t pixel_count) override {
95 compactor_.drawPixels(
97 [this, mode, colors](int16_t offset, int16_t x, int16_t y,
99 int16_t count) {
100 switch (direction) {
101 case Compactor::RIGHT: {
102 buffer_dev_.setAddress(x, y, x + count - 1, y, mode);
103 buffer_dev_.write(colors + offset, count);
104 target_.flushRect(buffer_raster_, x, y, x + count - 1, y);
105 break;
106 }
107 case Compactor::DOWN: {
108 buffer_dev_.setAddress(x, y, x, y + count - 1, mode);
109 buffer_dev_.write(colors + offset, count);
110 target_.flushRect(buffer_raster_, x, y, x, y + count - 1);
111 break;
112 }
113 case Compactor::LEFT: {
114 buffer_dev_.setAddress(x - count + 1, y, x, y, mode);
115 std::reverse(colors + offset, colors + offset + count);
116 buffer_dev_.write(colors + offset, count);
117 target_.flushRect(buffer_raster_, x - count + 1, y, x, y);
118 break;
119 }
120 case Compactor::UP: {
121 buffer_dev_.setAddress(x, y - count + 1, x, y, mode);
122 std::reverse(colors + offset, colors + offset + count);
123 buffer_dev_.write(colors + offset, count);
124 target_.flushRect(buffer_raster_, x, y - count + 1, x, y);
125 break;
126 }
127 }
128 });
129 }
130
132 uint16_t pixel_count) override {
133 compactor_.drawPixels(
134 xs, ys, pixel_count,
135 [this, mode, color](int16_t offset, int16_t x, int16_t y,
137 int16_t count) {
138 switch (direction) {
139 case Compactor::RIGHT: {
140 buffer_dev_.fillRect(mode, Box(x, y, x + count - 1, y), color);
141 target_.flushRect(buffer_raster_, x, y, x + count - 1, y);
142 break;
143 }
144 case Compactor::DOWN: {
145 buffer_dev_.fillRect(mode, Box(x, y, x, y + count - 1), color);
146 target_.flushRect(buffer_raster_, x, y, x, y + count - 1);
147 break;
148 }
149 case Compactor::LEFT: {
150 buffer_dev_.fillRect(mode, Box(x - count + 1, y, x, y), color);
151 target_.flushRect(buffer_raster_, x - count + 1, y, x, y);
152 break;
153 }
154 case Compactor::UP: {
155 buffer_dev_.fillRect(mode, Box(x, y - count + 1, x, y), color);
156 target_.flushRect(buffer_raster_, x, y - count + 1, x, y);
157 break;
158 }
159 }
160 });
161 }
162
163 const ColorFormat& getColorFormat() const override {
164 return buffer_dev_.getColorFormat();
165 }
166
167 const ColorMode& color_mode() const { return buffer_dev_.color_mode(); }
168
169 void orientationUpdated() override { target_.setOrientation(orientation()); }
170
171 static inline raw_color_type to_raw_color(Color color) {
172 typename Target::ColorMode mode;
173 return mode.fromArgbColor(color);
174 }
175
176 private:
177 class RectCache {
178 public:
179 void setWindow(int16_t x0, int16_t y0, int16_t x1, int16_t y1)
180 __attribute__((always_inline)) {
181 window_ = Box(x0, y0, x1, y1);
182 begin_ = end_ = 0;
183 }
184
185 void pixelsWritten(uint16_t count) { end_ += count; }
186
187 bool isDirty() const { return begin_ != end_; }
188
189 uint32_t dirtyPixelCount() const {
190 return static_cast<uint32_t>(end_ - begin_);
191 }
192
193 // Returns a next rectangle from the dirty segment that needs to be flushed,
194 // and adjusts the begin_ offset accordingly.
195 // Returns an empty rect when the dirty segment has already been entirely
196 // consumed.
197 Box consume() {
198 if (!isDirty()) return Box(0, 0, -1, -1);
199 if (begin_ != 0) {
200 // First line starts at offset; we need to return a dedicated horizontal
201 // rectangle to represent that.
202 uint32_t remaining = static_cast<uint32_t>(window_.width()) - begin_;
203 bool unfinished_line = dirtyPixelCount() < remaining;
204 if (unfinished_line) {
205 // There may come more pixels in this line later; we can't compact the
206 // window.
207 Box result(window_.xMin() + begin_, window_.yMin(),
208 window_.xMin() + end_ - 1, window_.yMin());
209 begin_ = end_;
210 return result;
211 } else {
212 // We can remove this line from the window.
213 Box result(window_.xMin() + begin_, window_.yMin(), window_.xMax(),
214 window_.yMin());
215 window_ = Box(window_.xMin(), window_.yMin() + 1, window_.xMax(),
216 window_.yMax());
217 begin_ = 0;
218 end_ -= window_.width();
219 return result;
220 }
221 } else {
222 int16_t full_lines = dirtyPixelCount() / window_.width();
223 if (full_lines > 0) {
224 Box result(window_.xMin(), window_.yMin(), window_.xMax(),
225 window_.yMin() + full_lines - 1);
226 // We leave at most one (the last, incomplete) line in the window.
227 window_ = Box(window_.xMin(), window_.yMin() + full_lines - 1,
228 window_.xMax(), window_.yMax());
229 end_ -= full_lines * window_.width();
230 return result;
231 } else {
232 // Last, incomplete line. The window must be one-line-tall at this
233 // point.
234 Box result(window_.xMin(), window_.yMin(), window_.xMin() + end_ - 1,
235 window_.yMin());
236 window_ = Box(window_.xMin(), window_.yMin() + full_lines,
237 window_.xMax(), window_.yMax());
238 begin_ = end_;
239 return result;
240 }
241 }
242 }
243
244 private:
245 Box window_;
246 int32_t begin_;
247 int32_t end_;
248 };
249
250 void flushRectCache() {
251 while (true) {
252 Box box = rect_cache_.consume();
253 if (box.empty()) return;
254 target_.flushRect(buffer_raster_, box.xMin(), box.yMin(), box.xMax(),
255 box.yMax());
256 }
257 }
258
259 Target target_;
260 std::unique_ptr<roo::byte[]> buffer_;
261 OffscreenDevice<typename Target::ColorMode> buffer_dev_;
262 ConstDramRaster<typename Target::ColorMode> buffer_raster_;
263 RectCache rect_cache_;
264 Compactor compactor_;
265};
266
267} // namespace roo_display
Axis-aligned integer rectangle.
Definition box.h:12
void fill(Color color, uint32_t pixel_count) override
Write pixel_count copies of the same color into the current address window.
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.
static raw_color_type to_raw_color(Color color)
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().
void write(Color *color, uint32_t pixel_count) override
Write pixels into the current address window.
void begin() override
Enter a write transaction.
void init() override
Initialize the display driver.
const ColorFormat & getColorFormat() const override
Return the native color format used by this device for direct drawing.
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 writeRects(BlendingMode 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 fillRects(BlendingMode 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.
static constexpr ColorPixelOrder pixel_order
void end() override
Finalize the previously entered write transaction, flushing any pending writes.
void orientationUpdated() override
Invoked when orientation() is updated.
BufferedAddrWindowDevice(Orientation orientation=Orientation::Default(), Target target=Target())
ColorStorageType< typename Target::ColorMode > raw_color_type
void fillPixels(BlendingMode 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.
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
void fillRect(BlendingMode blending_mode, const Box &rect, Color color)
Fill a single rectangle. Invalidates the address window.
Definition device.h:135
virtual void fill(Color color, uint32_t pixel_count)
Write pixel_count copies of the same color into the current address window.
Definition device.cpp:7
ColorMode & color_mode()
Access color mode.
Definition offscreen.h:394
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().
Definition offscreen.h:1381
void writeRects(BlendingMode 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.
Definition offscreen.h:1568
const ColorFormat & getColorFormat() const override
Return the native color format used by this device for direct drawing.
Definition offscreen.h:398
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.
Definition offscreen.h:185
void fillRects(BlendingMode 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.
Definition offscreen.h:1587
void write(Color *color, uint32_t pixel_count) override
Write pixels into the current address window.
Definition offscreen.h:1410
Represents the orientation of a display device.
Definition orientation.h:25
static constexpr Orientation Default()
Return the default orientation (RightDown).
Definition orientation.h:54
Defines 140 opaque HTML named colors.
BlendingMode
Porter-Duff style blending modes.
Definition blending.h:17
roo_io::ByteOrder ByteOrder
Definition byte_order.h:7