• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <maarten.lankhorst@linux.intel.com>
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 	igt_pipe_crc_free(data->pipe_crc);
165 	data->pipe_crc = igt_pipe_crc_new(data->gfx_fd, pipe, INTEL_PIPE_CRC_SOURCE_AUTO);
166 
167 	mode = igt_output_get_mode(output);
168 	w = mode->hdisplay;
169 	h = mode->vdisplay;
170 
171 	/* recreate all fbs if incompatible */
172 	if (data->xrgb_fb.width != w || data->xrgb_fb.height != h) {
173 		cairo_t *cr;
174 
175 		igt_remove_fb(data->gfx_fd, &data->xrgb_fb);
176 		igt_remove_fb(data->gfx_fd, &data->argb_fb_0);
177 		igt_remove_fb(data->gfx_fd, &data->argb_fb_cov_0);
178 		igt_remove_fb(data->gfx_fd, &data->argb_fb_7e);
179 		igt_remove_fb(data->gfx_fd, &data->argb_fb_fc);
180 		igt_remove_fb(data->gfx_fd, &data->argb_fb_cov_7e);
181 		igt_remove_fb(data->gfx_fd, &data->argb_fb_cov_fc);
182 		igt_remove_fb(data->gfx_fd, &data->argb_fb_100);
183 		igt_remove_fb(data->gfx_fd, &data->black_fb);
184 		igt_remove_fb(data->gfx_fd, &data->gray_fb);
185 
186 		igt_create_fb(data->gfx_fd, w, h,
187 			      DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
188 			      &data->xrgb_fb);
189 		draw_gradient(&data->xrgb_fb, w, h, 1.);
190 
191 		igt_create_fb(data->gfx_fd, w, h,
192 			      DRM_FORMAT_ARGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
193 			      &data->argb_fb_cov_0);
194 		draw_gradient_coverage(&data->argb_fb_cov_0, w, h, 0);
195 
196 		igt_create_fb(data->gfx_fd, w, h,
197 			      DRM_FORMAT_ARGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
198 			      &data->argb_fb_0);
199 
200 		cr = igt_get_cairo_ctx(data->gfx_fd, &data->argb_fb_0);
201 		cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
202 		igt_paint_color_alpha(cr, 0, 0, w, h, 0., 0., 0., 0.0);
203 		igt_put_cairo_ctx(data->gfx_fd, &data->argb_fb_0, cr);
204 
205 		igt_create_fb(data->gfx_fd, w, h,
206 			      DRM_FORMAT_ARGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
207 			      &data->argb_fb_7e);
208 		draw_squares(&data->argb_fb_7e, w, h, 126. / 255.);
209 
210 		igt_create_fb(data->gfx_fd, w, h,
211 			      DRM_FORMAT_ARGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
212 			      &data->argb_fb_cov_7e);
213 		draw_squares_coverage(&data->argb_fb_cov_7e, w, h, 0x7e);
214 
215 		igt_create_fb(data->gfx_fd, w, h,
216 			      DRM_FORMAT_ARGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
217 			      &data->argb_fb_fc);
218 		draw_squares(&data->argb_fb_fc, w, h, 252. / 255.);
219 
220 		igt_create_fb(data->gfx_fd, w, h,
221 			      DRM_FORMAT_ARGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
222 			      &data->argb_fb_cov_fc);
223 		draw_squares_coverage(&data->argb_fb_cov_fc, w, h, 0xfc);
224 
225 		igt_create_fb(data->gfx_fd, w, h,
226 			      DRM_FORMAT_ARGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
227 			      &data->argb_fb_100);
228 		draw_gradient(&data->argb_fb_100, w, h, 1.);
229 
230 		igt_create_fb(data->gfx_fd, w, h,
231 			      DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
232 			      &data->black_fb);
233 
234 		igt_create_color_fb(data->gfx_fd, w, h,
235 				    DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
236 				    .5, .5, .5, &data->gray_fb);
237 	}
238 
239 	igt_plane_set_fb(primary, &data->black_fb);
240 	/* reset alpha property to default */
241 	reset_alpha(display, pipe);
242 }
243 
basic_alpha(data_t * data,enum pipe pipe,igt_plane_t * plane)244 static void basic_alpha(data_t *data, enum pipe pipe, igt_plane_t *plane)
245 {
246 	igt_display_t *display = &data->display;
247 	igt_crc_t ref_crc, crc;
248 	int i;
249 
250 	/* Testcase 1: alpha = 0.0, plane should be transparant. */
251 	igt_display_commit2(display, COMMIT_ATOMIC);
252 	igt_pipe_crc_start(data->pipe_crc);
253 	igt_pipe_crc_get_single(data->pipe_crc, &ref_crc);
254 
255 	igt_plane_set_fb(plane, &data->argb_fb_0);
256 
257 	/* transparant fb should be transparant, no matter what.. */
258 	for (i = 7; i < 256; i += 8) {
259 		igt_plane_set_prop_value(plane, IGT_PLANE_ALPHA, i | (i << 8));
260 		igt_display_commit2(display, COMMIT_ATOMIC);
261 
262 		igt_pipe_crc_get_current(display->drm_fd, data->pipe_crc, &crc);
263 		igt_assert_crc_equal(&ref_crc, &crc);
264 	}
265 
266 	/* And test alpha = 0, should give same CRC, but doesn't on some i915 platforms. */
267 	igt_plane_set_prop_value(plane, IGT_PLANE_ALPHA, 0);
268 	igt_display_commit2(display, COMMIT_ATOMIC);
269 
270 	igt_pipe_crc_get_current(display->drm_fd, data->pipe_crc, &crc);
271 	igt_assert_crc_equal(&ref_crc, &crc);
272 
273 	igt_pipe_crc_stop(data->pipe_crc);
274 }
275 
argb_opaque(data_t * data,enum pipe pipe,igt_plane_t * plane)276 static void argb_opaque(data_t *data, enum pipe pipe, igt_plane_t *plane)
277 {
278 	igt_display_t *display = &data->display;
279 	igt_crc_t ref_crc, crc;
280 
281 	/* alpha = 1.0, plane should be fully opaque, test with an opaque fb */
282 	igt_plane_set_fb(plane, &data->xrgb_fb);
283 	igt_display_commit2(display, COMMIT_ATOMIC);
284 	igt_pipe_crc_collect_crc(data->pipe_crc, &ref_crc);
285 
286 	igt_plane_set_fb(plane, &data->argb_fb_100);
287 	igt_display_commit2(display, COMMIT_ATOMIC);
288 	igt_pipe_crc_collect_crc(data->pipe_crc, &crc);
289 
290 	igt_assert_crc_equal(&ref_crc, &crc);
291 }
292 
argb_transparant(data_t * data,enum pipe pipe,igt_plane_t * plane)293 static void argb_transparant(data_t *data, enum pipe pipe, igt_plane_t *plane)
294 {
295 	igt_display_t *display = &data->display;
296 	igt_crc_t ref_crc, crc;
297 
298 	/* alpha = 1.0, plane should be fully opaque, test with a transparant fb */
299 	igt_plane_set_fb(plane, NULL);
300 	igt_display_commit2(display, COMMIT_ATOMIC);
301 	igt_pipe_crc_collect_crc(data->pipe_crc, &ref_crc);
302 
303 	igt_plane_set_fb(plane, &data->argb_fb_0);
304 	igt_display_commit2(display, COMMIT_ATOMIC);
305 	igt_pipe_crc_collect_crc(data->pipe_crc, &crc);
306 
307 	igt_assert_crc_equal(&ref_crc, &crc);
308 }
309 
constant_alpha_min(data_t * data,enum pipe pipe,igt_plane_t * plane)310 static void constant_alpha_min(data_t *data, enum pipe pipe, igt_plane_t *plane)
311 {
312 	igt_display_t *display = &data->display;
313 	igt_crc_t ref_crc, crc;
314 
315 	igt_plane_set_fb(plane, NULL);
316 	igt_display_commit2(display, COMMIT_ATOMIC);
317 	igt_pipe_crc_collect_crc(data->pipe_crc, &ref_crc);
318 
319 	igt_plane_set_prop_enum(plane, IGT_PLANE_PIXEL_BLEND_MODE, "None");
320 	igt_plane_set_prop_value(plane, IGT_PLANE_ALPHA, 0);
321 	igt_plane_set_fb(plane, &data->argb_fb_100);
322 	igt_display_commit2(display, COMMIT_ATOMIC);
323 	igt_pipe_crc_collect_crc(data->pipe_crc, &crc);
324 	igt_assert_crc_equal(&ref_crc, &crc);
325 
326 	igt_plane_set_fb(plane, &data->argb_fb_0);
327 	igt_display_commit2(display, COMMIT_ATOMIC);
328 	igt_pipe_crc_collect_crc(data->pipe_crc, &crc);
329 	igt_assert_crc_equal(&ref_crc, &crc);
330 }
331 
constant_alpha_mid(data_t * data,enum pipe pipe,igt_plane_t * plane)332 static void constant_alpha_mid(data_t *data, enum pipe pipe, igt_plane_t *plane)
333 {
334 	igt_display_t *display = &data->display;
335 	igt_crc_t ref_crc, crc;
336 
337 	if (plane->type != DRM_PLANE_TYPE_PRIMARY)
338 		igt_plane_set_fb(igt_pipe_get_plane_type(&display->pipes[pipe], DRM_PLANE_TYPE_PRIMARY), &data->gray_fb);
339 
340 	igt_plane_set_prop_enum(plane, IGT_PLANE_PIXEL_BLEND_MODE, "None");
341 	igt_plane_set_prop_value(plane, IGT_PLANE_ALPHA, 0x7fff);
342 	igt_plane_set_fb(plane, &data->xrgb_fb);
343 	igt_display_commit2(display, COMMIT_ATOMIC);
344 	igt_pipe_crc_collect_crc(data->pipe_crc, &ref_crc);
345 
346 	igt_plane_set_fb(plane, &data->argb_fb_cov_0);
347 	igt_display_commit2(display, COMMIT_ATOMIC);
348 	igt_pipe_crc_collect_crc(data->pipe_crc, &crc);
349 	igt_assert_crc_equal(&ref_crc, &crc);
350 
351 	igt_plane_set_fb(plane, &data->argb_fb_100);
352 	igt_display_commit2(display, COMMIT_ATOMIC);
353 	igt_pipe_crc_collect_crc(data->pipe_crc, &crc);
354 	igt_assert_crc_equal(&ref_crc, &crc);
355 }
356 
constant_alpha_max(data_t * data,enum pipe pipe,igt_plane_t * plane)357 static void constant_alpha_max(data_t *data, enum pipe pipe, igt_plane_t *plane)
358 {
359 	igt_display_t *display = &data->display;
360 	igt_crc_t ref_crc, crc;
361 
362 	if (plane->type != DRM_PLANE_TYPE_PRIMARY)
363 		igt_plane_set_fb(igt_pipe_get_plane_type(&display->pipes[pipe], DRM_PLANE_TYPE_PRIMARY), &data->gray_fb);
364 
365 	igt_plane_set_fb(plane, &data->argb_fb_100);
366 	igt_display_commit2(display, COMMIT_ATOMIC);
367 	igt_pipe_crc_collect_crc(data->pipe_crc, &ref_crc);
368 
369 	igt_plane_set_prop_enum(plane, IGT_PLANE_PIXEL_BLEND_MODE, "None");
370 	igt_display_commit2(display, COMMIT_ATOMIC);
371 	igt_pipe_crc_collect_crc(data->pipe_crc, &crc);
372 	igt_assert_crc_equal(&ref_crc, &crc);
373 
374 	igt_plane_set_fb(plane, &data->argb_fb_cov_0);
375 	igt_display_commit2(display, COMMIT_ATOMIC);
376 	igt_pipe_crc_collect_crc(data->pipe_crc, &crc);
377 	igt_assert_crc_equal(&ref_crc, &crc);
378 
379 	igt_plane_set_fb(plane, &data->xrgb_fb);
380 	igt_display_commit2(display, COMMIT_ATOMIC);
381 	igt_pipe_crc_collect_crc(data->pipe_crc, &crc);
382 	igt_assert_crc_equal(&ref_crc, &crc);
383 
384 	igt_plane_set_fb(plane, NULL);
385 }
386 
alpha_7efc(data_t * data,enum pipe pipe,igt_plane_t * plane)387 static void alpha_7efc(data_t *data, enum pipe pipe, igt_plane_t *plane)
388 {
389 	igt_display_t *display = &data->display;
390 	igt_crc_t ref_crc = {}, crc = {};
391 	int i;
392 
393 	if (plane->type != DRM_PLANE_TYPE_PRIMARY)
394 		igt_plane_set_fb(igt_pipe_get_plane_type(&display->pipes[pipe], DRM_PLANE_TYPE_PRIMARY), &data->gray_fb);
395 
396 	igt_display_commit2(display, COMMIT_ATOMIC);
397 	igt_pipe_crc_start(data->pipe_crc);
398 
399 	/* for coverage, plane alpha and fb alpha should be swappable, so swap fb and alpha */
400 	for (i = 0; i < 256; i += 8) {
401 		igt_plane_set_prop_value(plane, IGT_PLANE_ALPHA, ((i/2) << 8) | (i/2));
402 		igt_plane_set_fb(plane, &data->argb_fb_fc);
403 		igt_display_commit2(display, COMMIT_ATOMIC);
404 
405 		igt_pipe_crc_get_current(display->drm_fd, data->pipe_crc, &ref_crc);
406 
407 		igt_plane_set_prop_value(plane, IGT_PLANE_ALPHA, (i << 8) | i);
408 		igt_plane_set_fb(plane, &data->argb_fb_7e);
409 		igt_display_commit2(display, COMMIT_ATOMIC);
410 
411 		igt_pipe_crc_get_current(display->drm_fd, data->pipe_crc, &crc);
412 		igt_assert_crc_equal(&ref_crc, &crc);
413 	}
414 
415 	igt_pipe_crc_stop(data->pipe_crc);
416 }
417 
coverage_7efc(data_t * data,enum pipe pipe,igt_plane_t * plane)418 static void coverage_7efc(data_t *data, enum pipe pipe, igt_plane_t *plane)
419 {
420 	igt_display_t *display = &data->display;
421 	igt_crc_t ref_crc = {}, crc = {};
422 	int i;
423 
424 	igt_plane_set_prop_enum(plane, IGT_PLANE_PIXEL_BLEND_MODE, "Coverage");
425 	igt_display_commit2(display, COMMIT_ATOMIC);
426 	igt_pipe_crc_start(data->pipe_crc);
427 
428 	/* for coverage, plane alpha and fb alpha should be swappable, so swap fb and alpha */
429 	for (i = 0; i < 256; i += 8) {
430 		igt_plane_set_prop_value(plane, IGT_PLANE_ALPHA, ((i/2) << 8) | (i/2));
431 		igt_plane_set_fb(plane, &data->argb_fb_cov_fc);
432 		igt_display_commit2(display, COMMIT_ATOMIC);
433 
434 		igt_pipe_crc_get_current(display->drm_fd, data->pipe_crc, &ref_crc);
435 
436 		igt_plane_set_prop_value(plane, IGT_PLANE_ALPHA, (i << 8) | i);
437 		igt_plane_set_fb(plane, &data->argb_fb_cov_7e);
438 		igt_display_commit2(display, COMMIT_ATOMIC);
439 
440 		igt_pipe_crc_get_current(display->drm_fd, data->pipe_crc, &crc);
441 		igt_assert_crc_equal(&ref_crc, &crc);
442 	}
443 
444 	igt_pipe_crc_stop(data->pipe_crc);
445 }
446 
coverage_premult_constant(data_t * data,enum pipe pipe,igt_plane_t * plane)447 static void coverage_premult_constant(data_t *data, enum pipe pipe, igt_plane_t *plane)
448 {
449 	igt_display_t *display = &data->display;
450 	igt_crc_t ref_crc = {}, crc = {};
451 
452 	/* Set a background color on the primary fb for testing */
453 	if (plane->type != DRM_PLANE_TYPE_PRIMARY)
454 		igt_plane_set_fb(igt_pipe_get_plane_type(&display->pipes[pipe], DRM_PLANE_TYPE_PRIMARY), &data->gray_fb);
455 
456 	igt_plane_set_prop_enum(plane, IGT_PLANE_PIXEL_BLEND_MODE, "Coverage");
457 	igt_plane_set_fb(plane, &data->argb_fb_cov_7e);
458 	igt_display_commit2(display, COMMIT_ATOMIC);
459 	igt_pipe_crc_start(data->pipe_crc);
460 	igt_pipe_crc_get_single(data->pipe_crc, &ref_crc);
461 
462 	igt_plane_set_prop_enum(plane, IGT_PLANE_PIXEL_BLEND_MODE, "Pre-multiplied");
463 	igt_plane_set_fb(plane, &data->argb_fb_7e);
464 	igt_display_commit2(display, COMMIT_ATOMIC);
465 	igt_pipe_crc_get_current(display->drm_fd, data->pipe_crc, &crc);
466 	igt_assert_crc_equal(&ref_crc, &crc);
467 
468 	igt_plane_set_prop_enum(plane, IGT_PLANE_PIXEL_BLEND_MODE, "None");
469 	igt_plane_set_prop_value(plane, IGT_PLANE_ALPHA, 0x7e7e);
470 	igt_plane_set_fb(plane, &data->argb_fb_cov_7e);
471 	igt_display_commit2(display, COMMIT_ATOMIC);
472 	igt_pipe_crc_get_current(display->drm_fd, data->pipe_crc, &crc);
473 	igt_assert_crc_equal(&ref_crc, &crc);
474 
475 	igt_pipe_crc_stop(data->pipe_crc);
476 }
477 
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 *))478 static void run_test_on_pipe_planes(data_t *data, enum pipe pipe, bool blend,
479 				    bool must_multiply,
480 				    void(*test)(data_t *, enum pipe, igt_plane_t *))
481 {
482 	igt_display_t *display = &data->display;
483 	igt_output_t *output = igt_get_single_output_for_pipe(display, pipe);
484 	igt_plane_t *plane;
485 	bool found = false;
486 	bool multiply = false;
487 
488 	for_each_plane_on_pipe(display, pipe, plane) {
489 		if (!igt_plane_has_prop(plane, IGT_PLANE_ALPHA))
490 			continue;
491 
492 		if (blend && !igt_plane_has_prop(plane, IGT_PLANE_PIXEL_BLEND_MODE))
493 			continue;
494 
495 		prepare_crtc(data, output, pipe);
496 
497 		/* reset plane alpha properties between each plane */
498 		reset_alpha(display, pipe);
499 
500 		found = true;
501 		if (must_multiply && !has_multiplied_alpha(data, plane))
502 			continue;
503 		multiply = true;
504 
505 		igt_info("Testing plane %u\n", plane->index);
506 		test(data, pipe, plane);
507 		igt_plane_set_fb(plane, NULL);
508 	}
509 
510 	igt_require_f(found, "No planes with %s property found\n",
511 		      blend ? "pixel blending mode" : "alpha");
512 	igt_require_f(multiply, "Multiplied (plane x pixel) alpha not available\n");
513 }
514 
run_subtests(data_t * data,enum pipe pipe)515 static void run_subtests(data_t *data, enum pipe pipe)
516 {
517 	igt_fixture {
518 		bool found = false;
519 		igt_plane_t *plane;
520 
521 		igt_display_require_output_on_pipe(&data->display, pipe);
522 		for_each_plane_on_pipe(&data->display, pipe, plane) {
523 			if (!igt_plane_has_prop(plane, IGT_PLANE_ALPHA))
524 				continue;
525 
526 			found = true;
527 			break;
528 		}
529 
530 		igt_require_f(found, "Found no plane on pipe %s with alpha blending supported\n",
531 			      kmstest_pipe_name(pipe));
532 	}
533 
534 	igt_subtest_f("pipe-%s-alpha-basic", kmstest_pipe_name(pipe))
535 		run_test_on_pipe_planes(data, pipe, false, true, basic_alpha);
536 
537 	igt_subtest_f("pipe-%s-alpha-7efc", kmstest_pipe_name(pipe))
538 		run_test_on_pipe_planes(data, pipe, false, true, alpha_7efc);
539 
540 	igt_subtest_f("pipe-%s-coverage-7efc", kmstest_pipe_name(pipe))
541 		run_test_on_pipe_planes(data, pipe, true, true, coverage_7efc);
542 
543 	igt_subtest_f("pipe-%s-coverage-vs-premult-vs-constant", kmstest_pipe_name(pipe))
544 		run_test_on_pipe_planes(data, pipe, true, false, coverage_premult_constant);
545 
546 	igt_subtest_f("pipe-%s-alpha-transparant-fb", kmstest_pipe_name(pipe))
547 		run_test_on_pipe_planes(data, pipe, false, false, argb_transparant);
548 
549 	igt_subtest_f("pipe-%s-alpha-opaque-fb", kmstest_pipe_name(pipe))
550 		run_test_on_pipe_planes(data, pipe, false, false, argb_opaque);
551 
552 	igt_subtest_f("pipe-%s-constant-alpha-min", kmstest_pipe_name(pipe))
553 		run_test_on_pipe_planes(data, pipe, true, false, constant_alpha_min);
554 
555 	igt_subtest_f("pipe-%s-constant-alpha-mid", kmstest_pipe_name(pipe))
556 		run_test_on_pipe_planes(data, pipe, true, false, constant_alpha_mid);
557 
558 	igt_subtest_f("pipe-%s-constant-alpha-max", kmstest_pipe_name(pipe))
559 		run_test_on_pipe_planes(data, pipe, true, false, constant_alpha_max);
560 }
561 
562 igt_main
563 {
564 	data_t data = {};
565 	enum pipe pipe;
566 
567 	igt_fixture {
568 		data.gfx_fd = drm_open_driver(DRIVER_ANY);
569 		igt_require_pipe_crc(data.gfx_fd);
570 		igt_display_require(&data.display, data.gfx_fd);
571 		igt_require(data.display.is_atomic);
572 	}
573 
574 	for_each_pipe_static(pipe)
575 		igt_subtest_group
576 			run_subtests(&data, pipe);
577 
578 	igt_fixture
579 		igt_display_fini(&data.display);
580 }
581