xref: /aosp_15_r20/external/igt-gpu-tools/tests/kms_plane_alpha_blend.c (revision d83cc019efdc2edc6c4b16e9034a3ceb8d35d77c)
1 /*
2  * Copyright © 2018 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  *
23  * Authors:
24  *   Maarten Lankhorst <[email protected]>
25  */
26 
27 #include "igt.h"
28 
29 IGT_TEST_DESCRIPTION("Test plane alpha and blending mode properties");
30 
31 typedef struct {
32 	int gfx_fd;
33 	igt_display_t display;
34 	struct igt_fb xrgb_fb, argb_fb_0, argb_fb_cov_0, argb_fb_7e, argb_fb_cov_7e, argb_fb_fc, argb_fb_cov_fc, argb_fb_100, black_fb, gray_fb;
35 	igt_crc_t ref_crc;
36 	igt_pipe_crc_t *pipe_crc;
37 } data_t;
38 
__draw_gradient(struct igt_fb * fb,int w,int h,double a,cairo_t * cr)39 static void __draw_gradient(struct igt_fb *fb, int w, int h, double a, cairo_t *cr)
40 {
41 	cairo_pattern_t *pat;
42 
43 	pat = cairo_pattern_create_linear(0, 0, w, h);
44 	cairo_pattern_add_color_stop_rgba(pat, 0.00, 0.00, 0.00, 0.00, 1.);
45 	cairo_pattern_add_color_stop_rgba(pat, 0.25, 1.00, 1.00, 0.00, 1.);
46 	cairo_pattern_add_color_stop_rgba(pat, 0.50, 0.00, 1.00, 1.00, 1.);
47 	cairo_pattern_add_color_stop_rgba(pat, 0.75, 1.00, 0.00, 1.00, 1.);
48 	cairo_pattern_add_color_stop_rgba(pat, 1.00, 1.00, 1.00, 1.00, 1.);
49 
50 	cairo_rectangle(cr, 0, 0, w, h);
51 	cairo_set_source(cr, pat);
52 	cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
53 	cairo_paint_with_alpha(cr, a);
54 	cairo_pattern_destroy(pat);
55 }
56 
draw_gradient(struct igt_fb * fb,int w,int h,double a)57 static void draw_gradient(struct igt_fb *fb, int w, int h, double a)
58 {
59 	cairo_t *cr = igt_get_cairo_ctx(fb->fd, fb);
60 
61 	__draw_gradient(fb, w, h, a, cr);
62 
63 	igt_put_cairo_ctx(fb->fd, fb, cr);
64 }
65 
draw_gradient_coverage(struct igt_fb * fb,int w,int h,uint8_t a)66 static void draw_gradient_coverage(struct igt_fb *fb, int w, int h, uint8_t a)
67 {
68 	cairo_t *cr = igt_get_cairo_ctx(fb->fd, fb);
69 	uint8_t *data = cairo_image_surface_get_data(fb->cairo_surface);
70 	uint32_t stride = fb->strides[0];
71 	int i;
72 
73 	__draw_gradient(fb, w, h, 1., cr);
74 
75 	for (; h--; data += stride)
76 		for (i = 0; i < w; i++)
77 			data[i * 4 + 3] = a;
78 
79 	igt_put_cairo_ctx(fb->fd, fb, cr);
80 }
81 
draw_squares(struct igt_fb * fb,int w,int h,double a)82 static void draw_squares(struct igt_fb *fb, int w, int h, double a)
83 {
84 	cairo_t *cr = igt_get_cairo_ctx(fb->fd, fb);
85 
86 	cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
87 	igt_paint_color_alpha(cr, 0, 0,         w / 2, h / 2, 1., 0., 0., a);
88 	igt_paint_color_alpha(cr, w / 2, 0,     w / 2, h / 2, 0., 1., 0., a);
89 	igt_paint_color_alpha(cr, 0, h / 2,     w / 2, h / 2, 0., 0., 1., a);
90 	igt_paint_color_alpha(cr, w / 2, h / 2, w / 4, h / 2, 1., 1., 1., a);
91 	igt_paint_color_alpha(cr, 3 * w / 4, h / 2, w / 4, h / 2, 0., 0., 0., a);
92 
93 	igt_put_cairo_ctx(fb->fd, fb, cr);
94 }
95 
draw_squares_coverage(struct igt_fb * fb,int w,int h,uint8_t as)96 static void draw_squares_coverage(struct igt_fb *fb, int w, int h, uint8_t as)
97 {
98 	cairo_t *cr = igt_get_cairo_ctx(fb->fd, fb);
99 	int i, j;
100 	uint32_t *data = (void *)cairo_image_surface_get_data(fb->cairo_surface);
101 	uint32_t stride = fb->strides[0] / 4;
102 	uint32_t a = as << 24;
103 
104 	for (j = 0; j < h / 2; j++) {
105 		for (i = 0; i < w / 2; i++)
106 			data[j * stride + i] = a | 0xff0000;
107 
108 		for (; i < w; i++)
109 			data[j * stride + i] = a | 0xff00;
110 	}
111 
112 	for (j = h / 2; j < h; j++) {
113 		for (i = 0; i < w / 2; i++)
114 			data[j * stride + i] = a | 0xff;
115 
116 		for (; i < 3 * w / 4; i++)
117 			data[j * stride + i] = a | 0xffffff;
118 
119 		for (; i < w; i++)
120 			data[j * stride + i] = a;
121 	}
122 
123 	igt_put_cairo_ctx(fb->fd, fb, cr);
124 }
125 
reset_alpha(igt_display_t * display,enum pipe pipe)126 static void reset_alpha(igt_display_t *display, enum pipe pipe)
127 {
128 	igt_plane_t *plane;
129 
130 	for_each_plane_on_pipe(display, pipe, plane) {
131 		if (igt_plane_has_prop(plane, IGT_PLANE_ALPHA))
132 			igt_plane_set_prop_value(plane, IGT_PLANE_ALPHA, 0xffff);
133 
134 		if (igt_plane_has_prop(plane, IGT_PLANE_PIXEL_BLEND_MODE))
135 			igt_plane_set_prop_enum(plane, IGT_PLANE_PIXEL_BLEND_MODE, "Pre-multiplied");
136 	}
137 }
138 
has_multiplied_alpha(data_t * data,igt_plane_t * plane)139 static bool has_multiplied_alpha(data_t *data, igt_plane_t *plane)
140 {
141 	int ret;
142 
143 	igt_plane_set_prop_value(plane, IGT_PLANE_ALPHA, 0x8080);
144 	igt_plane_set_fb(plane, &data->argb_fb_100);
145 	ret = igt_display_try_commit_atomic(&data->display,
146 		DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
147 	igt_plane_set_prop_value(plane, IGT_PLANE_ALPHA, 0xffff);
148 	igt_plane_set_fb(plane, NULL);
149 
150 	return ret == 0;
151 }
152 
prepare_crtc(data_t * data,igt_output_t * output,enum pipe pipe)153 static void prepare_crtc(data_t *data, igt_output_t *output, enum pipe pipe)
154 {
155 	drmModeModeInfo *mode;
156 	igt_display_t *display = &data->display;
157 	int w, h;
158 	igt_plane_t *primary = igt_pipe_get_plane_type(&display->pipes[pipe], DRM_PLANE_TYPE_PRIMARY);
159 
160 	igt_display_reset(display);
161 	igt_output_set_pipe(output, pipe);
162 
163 	/* create the pipe_crc object for this pipe */
164 
165 #if defined (USE_CRC)
166 	igt_pipe_crc_free(data->pipe_crc);
167 	data->pipe_crc = igt_pipe_crc_new(data->gfx_fd, pipe, INTEL_PIPE_CRC_SOURCE_AUTO);
168 #endif
169 
170 	mode = igt_output_get_mode(output);
171 	w = mode->hdisplay;
172 	h = mode->vdisplay;
173 
174 	/* recreate all fbs if incompatible */
175 	if (data->xrgb_fb.width != w || data->xrgb_fb.height != h) {
176 		cairo_t *cr;
177 
178 		igt_remove_fb(data->gfx_fd, &data->xrgb_fb);
179 		igt_remove_fb(data->gfx_fd, &data->argb_fb_0);
180 		igt_remove_fb(data->gfx_fd, &data->argb_fb_cov_0);
181 		igt_remove_fb(data->gfx_fd, &data->argb_fb_7e);
182 		igt_remove_fb(data->gfx_fd, &data->argb_fb_fc);
183 		igt_remove_fb(data->gfx_fd, &data->argb_fb_cov_7e);
184 		igt_remove_fb(data->gfx_fd, &data->argb_fb_cov_fc);
185 		igt_remove_fb(data->gfx_fd, &data->argb_fb_100);
186 		igt_remove_fb(data->gfx_fd, &data->black_fb);
187 		igt_remove_fb(data->gfx_fd, &data->gray_fb);
188 
189 		igt_create_fb(data->gfx_fd, w, h,
190 			      DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
191 			      &data->xrgb_fb);
192 		draw_gradient(&data->xrgb_fb, w, h, 1.);
193 
194 		igt_create_fb(data->gfx_fd, w, h,
195 			      DRM_FORMAT_ARGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
196 			      &data->argb_fb_cov_0);
197 		draw_gradient_coverage(&data->argb_fb_cov_0, w, h, 0);
198 
199 		igt_create_fb(data->gfx_fd, w, h,
200 			      DRM_FORMAT_ARGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
201 			      &data->argb_fb_0);
202 
203 		cr = igt_get_cairo_ctx(data->gfx_fd, &data->argb_fb_0);
204 		cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
205 		igt_paint_color_alpha(cr, 0, 0, w, h, 0., 0., 0., 0.0);
206 		igt_put_cairo_ctx(data->gfx_fd, &data->argb_fb_0, cr);
207 
208 		igt_create_fb(data->gfx_fd, w, h,
209 			      DRM_FORMAT_ARGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
210 			      &data->argb_fb_7e);
211 		draw_squares(&data->argb_fb_7e, w, h, 126. / 255.);
212 
213 		igt_create_fb(data->gfx_fd, w, h,
214 			      DRM_FORMAT_ARGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
215 			      &data->argb_fb_cov_7e);
216 		draw_squares_coverage(&data->argb_fb_cov_7e, w, h, 0x7e);
217 
218 		igt_create_fb(data->gfx_fd, w, h,
219 			      DRM_FORMAT_ARGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
220 			      &data->argb_fb_fc);
221 		draw_squares(&data->argb_fb_fc, w, h, 252. / 255.);
222 
223 		igt_create_fb(data->gfx_fd, w, h,
224 			      DRM_FORMAT_ARGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
225 			      &data->argb_fb_cov_fc);
226 		draw_squares_coverage(&data->argb_fb_cov_fc, w, h, 0xfc);
227 
228 		igt_create_fb(data->gfx_fd, w, h,
229 			      DRM_FORMAT_ARGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
230 			      &data->argb_fb_100);
231 		draw_gradient(&data->argb_fb_100, w, h, 1.);
232 
233 		igt_create_fb(data->gfx_fd, w, h,
234 			      DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
235 			      &data->black_fb);
236 
237 		igt_create_color_fb(data->gfx_fd, w, h,
238 				    DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
239 				    .5, .5, .5, &data->gray_fb);
240 	}
241 
242 	igt_plane_set_fb(primary, &data->black_fb);
243 	/* reset alpha property to default */
244 	reset_alpha(display, pipe);
245 }
246 
basic_alpha(data_t * data,enum pipe pipe,igt_plane_t * plane)247 static void basic_alpha(data_t *data, enum pipe pipe, igt_plane_t *plane)
248 {
249 	igt_display_t *display = &data->display;
250 	igt_crc_t ref_crc, crc;
251 	int i;
252 
253 	/* Testcase 1: alpha = 0.0, plane should be transparant. */
254 	igt_display_commit2(display, COMMIT_ATOMIC);
255 #if defined (USE_CRC)
256 	igt_pipe_crc_start(data->pipe_crc);
257 	igt_pipe_crc_get_single(data->pipe_crc, &ref_crc);
258 #endif
259 
260 	igt_plane_set_fb(plane, &data->argb_fb_0);
261 
262 	/* transparant fb should be transparant, no matter what.. */
263 	for (i = 7; i < 256; i += 8) {
264 		igt_plane_set_prop_value(plane, IGT_PLANE_ALPHA, i | (i << 8));
265 		igt_display_commit2(display, COMMIT_ATOMIC);
266 
267 #if defined (USE_CRC)
268 		igt_pipe_crc_get_current(display->drm_fd, data->pipe_crc, &crc);
269 		igt_assert_crc_equal(&ref_crc, &crc);
270 #endif
271 	}
272 
273 	/* And test alpha = 0, should give same CRC, but doesn't on some i915 platforms. */
274 	igt_plane_set_prop_value(plane, IGT_PLANE_ALPHA, 0);
275 	igt_display_commit2(display, COMMIT_ATOMIC);
276 
277 #if defined (USE_CRC)
278 	igt_pipe_crc_get_current(display->drm_fd, data->pipe_crc, &crc);
279 	igt_assert_crc_equal(&ref_crc, &crc);
280 
281 	igt_pipe_crc_stop(data->pipe_crc);
282 #endif
283 }
284 
argb_opaque(data_t * data,enum pipe pipe,igt_plane_t * plane)285 static void argb_opaque(data_t *data, enum pipe pipe, igt_plane_t *plane)
286 {
287 	igt_display_t *display = &data->display;
288 	igt_crc_t ref_crc, crc;
289 
290 	/* alpha = 1.0, plane should be fully opaque, test with an opaque fb */
291 	igt_plane_set_fb(plane, &data->xrgb_fb);
292 	igt_display_commit2(display, COMMIT_ATOMIC);
293 #if defined (USE_CRC)
294 	igt_pipe_crc_collect_crc(data->pipe_crc, &ref_crc);
295 #endif
296 
297 	igt_plane_set_fb(plane, &data->argb_fb_100);
298 	igt_display_commit2(display, COMMIT_ATOMIC);
299 #if defined (USE_CRC)
300 	igt_pipe_crc_collect_crc(data->pipe_crc, &crc);
301 
302 	igt_assert_crc_equal(&ref_crc, &crc);
303 #endif
304 }
305 
argb_transparant(data_t * data,enum pipe pipe,igt_plane_t * plane)306 static void argb_transparant(data_t *data, enum pipe pipe, igt_plane_t *plane)
307 {
308 	igt_display_t *display = &data->display;
309 	igt_crc_t ref_crc, crc;
310 
311 	/* alpha = 1.0, plane should be fully opaque, test with a transparant fb */
312 	igt_plane_set_fb(plane, NULL);
313 	igt_display_commit2(display, COMMIT_ATOMIC);
314 #if defined (USE_CRC)
315 	igt_pipe_crc_collect_crc(data->pipe_crc, &ref_crc);
316 #endif
317 
318 	igt_plane_set_fb(plane, &data->argb_fb_0);
319 	igt_display_commit2(display, COMMIT_ATOMIC);
320 #if defined (USE_CRC)
321 	igt_pipe_crc_collect_crc(data->pipe_crc, &crc);
322 
323 	igt_assert_crc_equal(&ref_crc, &crc);
324 #endif
325 }
326 
constant_alpha_min(data_t * data,enum pipe pipe,igt_plane_t * plane)327 static void constant_alpha_min(data_t *data, enum pipe pipe, igt_plane_t *plane)
328 {
329 	igt_display_t *display = &data->display;
330 	igt_crc_t ref_crc, crc;
331 
332 	igt_plane_set_fb(plane, NULL);
333 	igt_display_commit2(display, COMMIT_ATOMIC);
334 #if defined (USE_CRC)
335 	igt_pipe_crc_collect_crc(data->pipe_crc, &ref_crc);
336 #endif
337 
338 	igt_plane_set_prop_enum(plane, IGT_PLANE_PIXEL_BLEND_MODE, "None");
339 	igt_plane_set_prop_value(plane, IGT_PLANE_ALPHA, 0);
340 	igt_plane_set_fb(plane, &data->argb_fb_100);
341 	igt_display_commit2(display, COMMIT_ATOMIC);
342 #if defined (USE_CRC)
343 	igt_pipe_crc_collect_crc(data->pipe_crc, &crc);
344 	igt_assert_crc_equal(&ref_crc, &crc);
345 #endif
346 
347 	igt_plane_set_fb(plane, &data->argb_fb_0);
348 	igt_display_commit2(display, COMMIT_ATOMIC);
349 #if defined (USE_CRC)
350 	igt_pipe_crc_collect_crc(data->pipe_crc, &crc);
351 #endif
352 	igt_assert_crc_equal(&ref_crc, &crc);
353 }
354 
constant_alpha_mid(data_t * data,enum pipe pipe,igt_plane_t * plane)355 static void constant_alpha_mid(data_t *data, enum pipe pipe, igt_plane_t *plane)
356 {
357 	igt_display_t *display = &data->display;
358 	igt_crc_t ref_crc, crc;
359 
360 	if (plane->type != DRM_PLANE_TYPE_PRIMARY)
361 		igt_plane_set_fb(igt_pipe_get_plane_type(&display->pipes[pipe], DRM_PLANE_TYPE_PRIMARY), &data->gray_fb);
362 
363 	igt_plane_set_prop_enum(plane, IGT_PLANE_PIXEL_BLEND_MODE, "None");
364 	igt_plane_set_prop_value(plane, IGT_PLANE_ALPHA, 0x7fff);
365 	igt_plane_set_fb(plane, &data->xrgb_fb);
366 	igt_display_commit2(display, COMMIT_ATOMIC);
367 #if defined (USE_CRC)
368 	igt_pipe_crc_collect_crc(data->pipe_crc, &ref_crc);
369 #endif
370 
371 	igt_plane_set_fb(plane, &data->argb_fb_cov_0);
372 	igt_display_commit2(display, COMMIT_ATOMIC);
373 #if defined (USE_CRC)
374 	igt_pipe_crc_collect_crc(data->pipe_crc, &crc);
375 	igt_assert_crc_equal(&ref_crc, &crc);
376 #endif
377 
378 	igt_plane_set_fb(plane, &data->argb_fb_100);
379 	igt_display_commit2(display, COMMIT_ATOMIC);
380 #if defined (USE_CRC)
381 	igt_pipe_crc_collect_crc(data->pipe_crc, &crc);
382 	igt_assert_crc_equal(&ref_crc, &crc);
383 #endif
384 }
385 
constant_alpha_max(data_t * data,enum pipe pipe,igt_plane_t * plane)386 static void constant_alpha_max(data_t *data, enum pipe pipe, igt_plane_t *plane)
387 {
388 	igt_display_t *display = &data->display;
389 	igt_crc_t ref_crc, crc;
390 
391 	if (plane->type != DRM_PLANE_TYPE_PRIMARY)
392 		igt_plane_set_fb(igt_pipe_get_plane_type(&display->pipes[pipe], DRM_PLANE_TYPE_PRIMARY), &data->gray_fb);
393 
394 	igt_plane_set_fb(plane, &data->argb_fb_100);
395 	igt_display_commit2(display, COMMIT_ATOMIC);
396 #if defined (USE_CRC)
397 	igt_pipe_crc_collect_crc(data->pipe_crc, &ref_crc);
398 #endif
399 
400 	igt_plane_set_prop_enum(plane, IGT_PLANE_PIXEL_BLEND_MODE, "None");
401 	igt_display_commit2(display, COMMIT_ATOMIC);
402 #if defined (USE_CRC)
403 	igt_pipe_crc_collect_crc(data->pipe_crc, &crc);
404 	igt_assert_crc_equal(&ref_crc, &crc);
405 #endif
406 
407 	igt_plane_set_fb(plane, &data->argb_fb_cov_0);
408 	igt_display_commit2(display, COMMIT_ATOMIC);
409 #if defined (USE_CRC)
410 	igt_pipe_crc_collect_crc(data->pipe_crc, &crc);
411 	igt_assert_crc_equal(&ref_crc, &crc);
412 #endif
413 
414 	igt_plane_set_fb(plane, &data->xrgb_fb);
415 	igt_display_commit2(display, COMMIT_ATOMIC);
416 #if defined (USE_CRC)
417 	igt_pipe_crc_collect_crc(data->pipe_crc, &crc);
418 	igt_assert_crc_equal(&ref_crc, &crc);
419 #endif
420 
421 	igt_plane_set_fb(plane, NULL);
422 }
423 
alpha_7efc(data_t * data,enum pipe pipe,igt_plane_t * plane)424 static void alpha_7efc(data_t *data, enum pipe pipe, igt_plane_t *plane)
425 {
426 	igt_display_t *display = &data->display;
427 	igt_crc_t ref_crc = {}, crc = {};
428 	int i;
429 
430 	if (plane->type != DRM_PLANE_TYPE_PRIMARY)
431 		igt_plane_set_fb(igt_pipe_get_plane_type(&display->pipes[pipe], DRM_PLANE_TYPE_PRIMARY), &data->gray_fb);
432 
433 	igt_display_commit2(display, COMMIT_ATOMIC);
434 #if defined (USE_CRC)
435 	igt_pipe_crc_start(data->pipe_crc);
436 #endif
437 
438 	/* for coverage, plane alpha and fb alpha should be swappable, so swap fb and alpha */
439 	for (i = 0; i < 256; i += 8) {
440 		igt_plane_set_prop_value(plane, IGT_PLANE_ALPHA, ((i/2) << 8) | (i/2));
441 		igt_plane_set_fb(plane, &data->argb_fb_fc);
442 		igt_display_commit2(display, COMMIT_ATOMIC);
443 
444 #if defined (USE_CRC)
445 		igt_pipe_crc_get_current(display->drm_fd, data->pipe_crc, &ref_crc);
446 #endif
447 
448 		igt_plane_set_prop_value(plane, IGT_PLANE_ALPHA, (i << 8) | i);
449 		igt_plane_set_fb(plane, &data->argb_fb_7e);
450 		igt_display_commit2(display, COMMIT_ATOMIC);
451 
452 #if defined (USE_CRC)
453 		igt_pipe_crc_get_current(display->drm_fd, data->pipe_crc, &crc);
454 		igt_assert_crc_equal(&ref_crc, &crc);
455 #endif
456 	}
457 
458 #if defined (USE_CRC)
459 	igt_pipe_crc_stop(data->pipe_crc);
460 #endif
461 }
462 
coverage_7efc(data_t * data,enum pipe pipe,igt_plane_t * plane)463 static void coverage_7efc(data_t *data, enum pipe pipe, igt_plane_t *plane)
464 {
465 	igt_display_t *display = &data->display;
466 	igt_crc_t ref_crc = {}, crc = {};
467 	int i;
468 
469 	igt_plane_set_prop_enum(plane, IGT_PLANE_PIXEL_BLEND_MODE, "Coverage");
470 	igt_display_commit2(display, COMMIT_ATOMIC);
471 #if defined (USE_CRC)
472 	igt_pipe_crc_start(data->pipe_crc);
473 #endif
474 
475 	/* for coverage, plane alpha and fb alpha should be swappable, so swap fb and alpha */
476 	for (i = 0; i < 256; i += 8) {
477 		igt_plane_set_prop_value(plane, IGT_PLANE_ALPHA, ((i/2) << 8) | (i/2));
478 		igt_plane_set_fb(plane, &data->argb_fb_cov_fc);
479 		igt_display_commit2(display, COMMIT_ATOMIC);
480 
481 #if defined (USE_CRC)
482 		igt_pipe_crc_get_current(display->drm_fd, data->pipe_crc, &ref_crc);
483 #endif
484 
485 		igt_plane_set_prop_value(plane, IGT_PLANE_ALPHA, (i << 8) | i);
486 		igt_plane_set_fb(plane, &data->argb_fb_cov_7e);
487 		igt_display_commit2(display, COMMIT_ATOMIC);
488 
489 #if defined (USE_CRC)
490 		igt_pipe_crc_get_current(display->drm_fd, data->pipe_crc, &crc);
491 		igt_assert_crc_equal(&ref_crc, &crc);
492 #endif
493 	}
494 
495 #if defined (USE_CRC)
496 	igt_pipe_crc_stop(data->pipe_crc);
497 #endif
498 }
499 
coverage_premult_constant(data_t * data,enum pipe pipe,igt_plane_t * plane)500 static void coverage_premult_constant(data_t *data, enum pipe pipe, igt_plane_t *plane)
501 {
502 	igt_display_t *display = &data->display;
503 	igt_crc_t ref_crc = {}, crc = {};
504 
505 	/* Set a background color on the primary fb for testing */
506 	if (plane->type != DRM_PLANE_TYPE_PRIMARY)
507 		igt_plane_set_fb(igt_pipe_get_plane_type(&display->pipes[pipe], DRM_PLANE_TYPE_PRIMARY), &data->gray_fb);
508 
509 	igt_plane_set_prop_enum(plane, IGT_PLANE_PIXEL_BLEND_MODE, "Coverage");
510 	igt_plane_set_fb(plane, &data->argb_fb_cov_7e);
511 	igt_display_commit2(display, COMMIT_ATOMIC);
512 #if defined (USE_CRC)
513 	igt_pipe_crc_start(data->pipe_crc);
514 	igt_pipe_crc_get_single(data->pipe_crc, &ref_crc);
515 #endif
516 
517 	igt_plane_set_prop_enum(plane, IGT_PLANE_PIXEL_BLEND_MODE, "Pre-multiplied");
518 	igt_plane_set_fb(plane, &data->argb_fb_7e);
519 	igt_display_commit2(display, COMMIT_ATOMIC);
520 #if defined (USE_CRC)
521 	igt_pipe_crc_get_current(display->drm_fd, data->pipe_crc, &crc);
522 	igt_assert_crc_equal(&ref_crc, &crc);
523 #endif
524 
525 	igt_plane_set_prop_enum(plane, IGT_PLANE_PIXEL_BLEND_MODE, "None");
526 	igt_plane_set_prop_value(plane, IGT_PLANE_ALPHA, 0x7e7e);
527 	igt_plane_set_fb(plane, &data->argb_fb_cov_7e);
528 	igt_display_commit2(display, COMMIT_ATOMIC);
529 #if defined (USE_CRC)
530 	igt_pipe_crc_get_current(display->drm_fd, data->pipe_crc, &crc);
531 	igt_assert_crc_equal(&ref_crc, &crc);
532 
533 	igt_pipe_crc_stop(data->pipe_crc);
534 #endif
535 }
536 
run_test_on_pipe_planes(data_t * data,enum pipe pipe,bool blend,bool must_multiply,void (* test)(data_t *,enum pipe,igt_plane_t *))537 static void run_test_on_pipe_planes(data_t *data, enum pipe pipe, bool blend,
538 				    bool must_multiply,
539 				    void(*test)(data_t *, enum pipe, igt_plane_t *))
540 {
541 	igt_display_t *display = &data->display;
542 	igt_output_t *output = igt_get_single_output_for_pipe(display, pipe);
543 	igt_plane_t *plane;
544 	bool found = false;
545 	bool multiply = false;
546 
547 	for_each_plane_on_pipe(display, pipe, plane) {
548 		if (!igt_plane_has_prop(plane, IGT_PLANE_ALPHA))
549 			continue;
550 
551 		if (blend && !igt_plane_has_prop(plane, IGT_PLANE_PIXEL_BLEND_MODE))
552 			continue;
553 
554 		prepare_crtc(data, output, pipe);
555 
556 		/* reset plane alpha properties between each plane */
557 		reset_alpha(display, pipe);
558 
559 		found = true;
560 		if (must_multiply && !has_multiplied_alpha(data, plane))
561 			continue;
562 		multiply = true;
563 
564 		igt_info("Testing plane %u\n", plane->index);
565 		test(data, pipe, plane);
566 		igt_plane_set_fb(plane, NULL);
567 	}
568 
569 	igt_require_f(found, "No planes with %s property found\n",
570 		      blend ? "pixel blending mode" : "alpha");
571 	igt_require_f(multiply, "Multiplied (plane x pixel) alpha not available\n");
572 }
573 
run_subtests(data_t * data,enum pipe pipe)574 static void run_subtests(data_t *data, enum pipe pipe)
575 {
576 	igt_fixture {
577 		bool found = false;
578 		igt_plane_t *plane;
579 
580 		igt_display_require_output_on_pipe(&data->display, pipe);
581 		for_each_plane_on_pipe(&data->display, pipe, plane) {
582 			if (!igt_plane_has_prop(plane, IGT_PLANE_ALPHA))
583 				continue;
584 
585 			found = true;
586 			break;
587 		}
588 
589 		igt_require_f(found, "Found no plane on pipe %s with alpha blending supported\n",
590 			      kmstest_pipe_name(pipe));
591 	}
592 
593 	igt_subtest_f("pipe-%s-alpha-basic", kmstest_pipe_name(pipe))
594 		run_test_on_pipe_planes(data, pipe, false, true, basic_alpha);
595 
596 	igt_subtest_f("pipe-%s-alpha-7efc", kmstest_pipe_name(pipe))
597 		run_test_on_pipe_planes(data, pipe, false, true, alpha_7efc);
598 
599 	igt_subtest_f("pipe-%s-coverage-7efc", kmstest_pipe_name(pipe))
600 		run_test_on_pipe_planes(data, pipe, true, true, coverage_7efc);
601 
602 	igt_subtest_f("pipe-%s-coverage-vs-premult-vs-constant", kmstest_pipe_name(pipe))
603 		run_test_on_pipe_planes(data, pipe, true, false, coverage_premult_constant);
604 
605 	igt_subtest_f("pipe-%s-alpha-transparant-fb", kmstest_pipe_name(pipe))
606 		run_test_on_pipe_planes(data, pipe, false, false, argb_transparant);
607 
608 	igt_subtest_f("pipe-%s-alpha-opaque-fb", kmstest_pipe_name(pipe))
609 		run_test_on_pipe_planes(data, pipe, false, false, argb_opaque);
610 
611 	igt_subtest_f("pipe-%s-constant-alpha-min", kmstest_pipe_name(pipe))
612 		run_test_on_pipe_planes(data, pipe, true, false, constant_alpha_min);
613 
614 	igt_subtest_f("pipe-%s-constant-alpha-mid", kmstest_pipe_name(pipe))
615 		run_test_on_pipe_planes(data, pipe, true, false, constant_alpha_mid);
616 
617 	igt_subtest_f("pipe-%s-constant-alpha-max", kmstest_pipe_name(pipe))
618 		run_test_on_pipe_planes(data, pipe, true, false, constant_alpha_max);
619 }
620 
621 igt_main
622 {
623 	data_t data = {};
624 	enum pipe pipe;
625 
626 	igt_fixture {
627 		data.gfx_fd = drm_open_driver(DRIVER_ANY);
628 #if defined (USE_CRC)
629 		igt_require_pipe_crc(data.gfx_fd);
630 #endif
631 		igt_display_require(&data.display, data.gfx_fd);
632 		igt_require(data.display.is_atomic);
633 	}
634 
635 	for_each_pipe_static(pipe)
636 		igt_subtest_group
637 			run_subtests(&data, pipe);
638 
639 	igt_fixture
640 		igt_display_fini(&data.display);
641 }
642