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