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