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