1 /*
2 * Copyright 2024 (c) TOKITA Hiroshi
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/drivers/display.h>
8 #include <zephyr/ztest.h>
9 #include <zephyr/device.h>
10 #include <zephyr/logging/log.h>
11 #include <zephyr/sys/util.h>
12
13 LOG_MODULE_DECLARE(display_api, CONFIG_DISPLAY_LOG_LEVEL);
14
15 static const struct device *dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display));
16 static const uint32_t display_width = DT_PROP(DT_CHOSEN(zephyr_display), width);
17 static const uint32_t display_height = DT_PROP(DT_CHOSEN(zephyr_display), height);
18 #ifdef CONFIG_DISPLAY_BUFFER_USE_GENERIC_SECTION
19 Z_GENERIC_SECTION(CONFIG_DISPLAY_BUFFER_SECTION)
20 #endif
21 static uint8_t disp_buffer[DT_PROP(DT_CHOSEN(zephyr_display), width) *
22 DT_PROP(DT_CHOSEN(zephyr_display), height) * 4]
23 __aligned(CONFIG_DISPLAY_BUFFER_ALIGNMENT);
24 static struct display_capabilities cfg;
25 static uint8_t bpp;
26 static bool is_vtiled;
27 static bool is_htiled;
28
buffer_size(size_t width,size_t height)29 static inline size_t buffer_size(size_t width, size_t height)
30 {
31 if (is_vtiled || is_htiled) {
32 return DIV_ROUND_UP(width * height, 8U);
33 }
34
35 return width * height * bpp;
36 }
37
bytes_per_pixel(enum display_pixel_format pixel_format)38 static inline uint8_t bytes_per_pixel(enum display_pixel_format pixel_format)
39 {
40 switch (pixel_format) {
41 case PIXEL_FORMAT_ARGB_8888:
42 return 4;
43 case PIXEL_FORMAT_RGB_888:
44 return 3;
45 case PIXEL_FORMAT_RGB_565:
46 case PIXEL_FORMAT_BGR_565:
47 case PIXEL_FORMAT_AL_88:
48 return 2;
49 case PIXEL_FORMAT_L_8:
50 case PIXEL_FORMAT_MONO01:
51 case PIXEL_FORMAT_MONO10:
52 default:
53 return 1;
54 }
55
56 return 0;
57 }
58
verify_bytes_of_area(uint8_t * data,int cmp_x,int cmp_y,size_t width,size_t height)59 static void verify_bytes_of_area(uint8_t *data, int cmp_x, int cmp_y, size_t width, size_t height)
60 {
61 struct display_buffer_descriptor desc = {
62 .height = height,
63 .pitch = width,
64 .width = width,
65 .buf_size = buffer_size(width, height),
66 };
67
68 int err = display_read(dev, cmp_x, cmp_y, &desc, disp_buffer);
69
70 zassert_ok(err, "display_read failed");
71
72 zassert_mem_equal(data, disp_buffer, buffer_size(width, height));
73 }
74
verify_background_color(int x,int y,size_t width,size_t height,uint32_t color)75 static void verify_background_color(int x, int y, size_t width, size_t height, uint32_t color)
76 {
77 size_t buf_size = buffer_size(width, height);
78 struct display_buffer_descriptor desc = {
79 .height = height,
80 .pitch = width,
81 .width = width,
82 .buf_size = buf_size,
83 };
84 uint32_t *buf32 = (void *)disp_buffer;
85 uint16_t *buf16 = (void *)disp_buffer;
86 uint8_t *buf8 = disp_buffer;
87 int err;
88
89 err = display_read(dev, x, y, &desc, disp_buffer);
90 zassert_ok(err, "display_read failed");
91
92 for (size_t i = 0; i < width * height; i++) {
93 switch (bpp) {
94 case 4:
95 zassert_equal(buf32[i], color, "@%d", i);
96 break;
97 case 2:
98 zassert_equal(buf16[i], (uint16_t)color, "@%d", i);
99 break;
100 case 1:
101 if (is_vtiled) {
102 uint16_t x = i % (width);
103 uint16_t line = (i - x) / width;
104 uint16_t tile = line / 8;
105 uint16_t y = line % 8;
106
107 uint8_t *tptr = disp_buffer + (tile * width + x);
108
109 zassert_equal(!!(*tptr & BIT(y)), !!(color), "@%d", i);
110 } else if (is_htiled) {
111 uint8_t *tptr = disp_buffer + i / 8;
112
113 zassert_equal(!!(*tptr & BIT(i % 8)), !!(color), "@%d", i);
114 } else {
115 zassert_equal(buf8[i], (uint8_t)color, "@%d", i);
116 }
117 break;
118 }
119 }
120 }
121
122 /**
123 * Fill the buffer with 0 before running tests.
124 */
display_before(void * text_fixture)125 static void display_before(void *text_fixture)
126 {
127 display_get_capabilities(dev, &cfg);
128 bpp = bytes_per_pixel(cfg.current_pixel_format);
129 is_vtiled = (bpp == 1 && (cfg.screen_info & SCREEN_INFO_MONO_VTILED));
130 is_htiled = (bpp == 1 && !(cfg.screen_info & SCREEN_INFO_MONO_VTILED));
131
132 struct display_buffer_descriptor desc = {
133 .height = display_height,
134 .pitch = display_width,
135 .width = display_width,
136 .buf_size = display_height * display_width * bpp,
137 };
138
139 memset(disp_buffer, 0, sizeof(disp_buffer));
140 display_write(dev, 0, 0, &desc, disp_buffer);
141 }
142
143 /*
144 * Verify that we can get a color of '0' from all pixels
145 * when after zeroing the buffer.
146 */
ZTEST(display_read_write,test_clear)147 ZTEST(display_read_write, test_clear)
148 {
149 verify_background_color(0, 0, display_width, display_height, 0);
150 }
151
152 /*
153 * Write to the head of the buffer and check that
154 * the same value can be read.
155 */
ZTEST(display_read_write,test_write_to_buffer_head)156 ZTEST(display_read_write, test_write_to_buffer_head)
157 {
158 uint8_t data[4] = {0xFA, 0xAF, 0x9F, 0xFA};
159 uint8_t height = (is_vtiled ? 8 : 1);
160 uint16_t width = sizeof(data) / bpp * (is_htiled ? 8 : 1);
161 uint16_t buf_size = width * bpp;
162 struct display_buffer_descriptor desc = {
163 .height = height,
164 .pitch = width,
165 .width = width,
166 .buf_size = buf_size,
167 };
168
169 /* write data to head of buffer */
170 display_write(dev, 0, 0, &desc, data);
171
172 /* check write data and read data are same */
173 verify_bytes_of_area(data, 0, 0, width, height);
174
175 /* check remaining region still black */
176 verify_background_color(0, height, display_width, display_height - height, 0);
177 verify_background_color(width, 0, display_width - width, display_height, 0);
178 }
179
180 /*
181 * Write to the tail of the buffer and check that
182 * the same value can be read.
183 */
ZTEST(display_read_write,test_write_to_buffer_tail)184 ZTEST(display_read_write, test_write_to_buffer_tail)
185 {
186 uint8_t data[4] = {0xFA, 0xAF, 0x9F, 0xFA};
187 uint16_t height = (is_vtiled ? 8 : 1);
188 uint16_t width = sizeof(data) / bpp * (is_htiled ? 8 : 1);
189 uint16_t buf_size = width * bpp;
190 struct display_buffer_descriptor desc = {
191 .height = height,
192 .pitch = width,
193 .width = width,
194 .buf_size = buf_size,
195 };
196 struct display_buffer_descriptor desc_whole = {
197 .height = display_height,
198 .pitch = display_width,
199 .width = display_width,
200 .buf_size = buffer_size(display_width, display_height),
201 };
202 int err;
203
204 /* write data to tail of buffer */
205 display_write(dev, display_width - width, display_height - height, &desc, data);
206
207 /* read entire displayed data */
208 err = display_read(dev, 0, 0, &desc_whole, disp_buffer);
209 zassert_ok(err, "display_read failed");
210
211 /* check write data and read data are same */
212 size_t total_bytes = buffer_size(display_width, display_height);
213 size_t area_bytes = buffer_size(width, height);
214 uint8_t *compare = disp_buffer + (total_bytes - area_bytes);
215
216 zassert_mem_equal(data, compare, area_bytes);
217
218 /* check remaining region still black */
219 verify_background_color(0, 0, display_width, display_height - height, 0);
220 verify_background_color(0, display_height - height, display_width - width, height, 0);
221 }
222
223 /*
224 * Verify that it will keep the drawn content even if display_read is executed
225 */
ZTEST(display_read_write,test_read_does_not_clear_existing_buffer)226 ZTEST(display_read_write, test_read_does_not_clear_existing_buffer)
227 {
228 uint8_t data[4] = {0xFA, 0xAF, 0x9F, 0xFA};
229 uint8_t height = (is_vtiled ? 8 : 1);
230 uint16_t width = sizeof(data) / bpp * (is_htiled ? 8 : 1);
231 uint16_t buf_size = width * bpp;
232 struct display_buffer_descriptor desc = {
233 .height = height,
234 .pitch = width,
235 .width = width,
236 .buf_size = buf_size,
237 };
238 struct display_buffer_descriptor desc_whole = {
239 .height = display_height,
240 .pitch = display_width,
241 .width = display_width,
242 .buf_size = buffer_size(display_width, display_height),
243 };
244 int err;
245
246 /* write data to head of buffer */
247 display_write(dev, 0, 0, &desc, data);
248
249 /* check write data and read data are same */
250 verify_bytes_of_area(data, 0, 0, width, height);
251
252 /* check remaining region still black */
253 verify_background_color(0, height, display_width, display_height - height, 0);
254 verify_background_color(width, 0, display_width - width, display_height, 0);
255
256 /* write data to tail of buffer */
257 display_write(dev, display_width - width, display_height - height, &desc, data);
258
259 /* read entire displayed data */
260 err = display_read(dev, 0, 0, &desc_whole, disp_buffer);
261 zassert_ok(err, "display_read failed");
262
263 /* checking correctly write to the tail of buffer */
264 size_t total_bytes = buffer_size(display_width, display_height);
265 size_t area_bytes = buffer_size(width, height);
266 uint8_t *compare = disp_buffer + (total_bytes - area_bytes);
267
268 zassert_mem_equal(data, compare, area_bytes);
269
270 /* checking if the content written before reading is kept */
271 verify_bytes_of_area(data, 0, 0, width, height);
272
273 /* checking remaining region is still black */
274 verify_background_color(width, 0, display_width - width, display_height - height, 0);
275 verify_background_color(0, height, display_width - width, display_height - height, 0);
276 }
277
278 ZTEST_SUITE(display_read_write, NULL, NULL, display_before, NULL, NULL);
279