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