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