1 /*
2  * Copyright © 2015 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  */
24 
25 #include <math.h>
26 #include <unistd.h>
27 
28 #include "drm.h"
29 #include "drmtest.h"
30 #include "igt.h"
31 
32 IGT_TEST_DESCRIPTION("Test Color Features at Pipe level");
33 
34 /* Internal */
35 typedef struct {
36 	double r, g, b;
37 } color_t;
38 
39 typedef struct {
40 	int drm_fd;
41 	uint32_t devid;
42 	igt_display_t display;
43 	igt_pipe_crc_t *pipe_crc;
44 
45 	uint32_t color_depth;
46 	uint64_t degamma_lut_size;
47 	uint64_t gamma_lut_size;
48 } data_t;
49 
50 typedef struct {
51 	int size;
52 	double coeffs[];
53 } gamma_lut_t;
54 
paint_gradient_rectangles(data_t * data,drmModeModeInfo * mode,color_t * colors,struct igt_fb * fb)55 static void paint_gradient_rectangles(data_t *data,
56 				      drmModeModeInfo *mode,
57 				      color_t *colors,
58 				      struct igt_fb *fb)
59 {
60 	cairo_t *cr = igt_get_cairo_ctx(data->drm_fd, fb);
61 	int i, l = mode->hdisplay / 3;
62 	int rows_remaining = mode->hdisplay % 3;
63 
64 	/* Paint 3 gradient rectangles with red/green/blue between 1.0 and
65 	 * 0.5. We want to avoid 0 so each max LUTs only affect their own
66 	 * rectangle.
67 	 */
68 	for (i = 0 ; i < 3; i++) {
69 		igt_paint_color_gradient_range(cr, i * l, 0, l, mode->vdisplay,
70 					       colors[i].r != 0 ? 0.2 : 0,
71 					       colors[i].g != 0 ? 0.2 : 0,
72 					       colors[i].b != 0 ? 0.2 : 0,
73 					       colors[i].r,
74 					       colors[i].g,
75 					       colors[i].b);
76 	}
77 
78 	if (rows_remaining > 0)
79 		igt_paint_color_gradient_range(cr, i * l, 0, rows_remaining,
80 					       mode->vdisplay,
81 					       colors[i-1].r != 0 ? 0.2 : 0,
82 					       colors[i-1].g != 0 ? 0.2 : 0,
83 					       colors[i-1].b != 0 ? 0.2 : 0,
84 					       colors[i-1].r,
85 					       colors[i-1].g,
86 					       colors[i-1].b);
87 
88 	igt_put_cairo_ctx(data->drm_fd, fb, cr);
89 }
90 
paint_rectangles(data_t * data,drmModeModeInfo * mode,color_t * colors,struct igt_fb * fb)91 static void paint_rectangles(data_t *data,
92 			     drmModeModeInfo *mode,
93 			     color_t *colors,
94 			     struct igt_fb *fb)
95 {
96 	cairo_t *cr = igt_get_cairo_ctx(data->drm_fd, fb);
97 	int i, l = mode->hdisplay / 3;
98 	int rows_remaining = mode->hdisplay % 3;
99 
100 	/* Paint 3 solid rectangles. */
101 	for (i = 0 ; i < 3; i++) {
102 		igt_paint_color(cr, i * l, 0, l, mode->vdisplay,
103 				colors[i].r, colors[i].g, colors[i].b);
104 	}
105 
106 	if (rows_remaining > 0)
107 		igt_paint_color(cr, i * l, 0, rows_remaining, mode->vdisplay,
108 				colors[i-1].r, colors[i-1].g, colors[i-1].b);
109 
110 	igt_put_cairo_ctx(data->drm_fd, fb, cr);
111 }
112 
alloc_lut(int lut_size)113 static gamma_lut_t *alloc_lut(int lut_size)
114 {
115 	gamma_lut_t *gamma;
116 
117 	igt_assert_lt(0, lut_size);
118 
119 	gamma = malloc(sizeof(*gamma) + lut_size * sizeof(gamma->coeffs[0]));
120 	igt_assert(gamma);
121 	gamma->size = lut_size;
122 
123 	return gamma;
124 }
125 
free_lut(gamma_lut_t * gamma)126 static void free_lut(gamma_lut_t *gamma)
127 {
128 	if (!gamma)
129 		return;
130 
131 	free(gamma);
132 }
133 
generate_table(int lut_size,double exp)134 static gamma_lut_t *generate_table(int lut_size, double exp)
135 {
136 	gamma_lut_t *gamma = alloc_lut(lut_size);
137 	int i;
138 
139 	gamma->coeffs[0] = 0.0;
140 	for (i = 1; i < lut_size; i++)
141 		gamma->coeffs[i] = pow(i * 1.0 / (lut_size - 1), exp);
142 
143 	return gamma;
144 }
145 
generate_table_max(int lut_size)146 static gamma_lut_t *generate_table_max(int lut_size)
147 {
148 	gamma_lut_t *gamma = alloc_lut(lut_size);
149 	int i;
150 
151 	gamma->coeffs[0] = 0.0;
152 	for (i = 1; i < lut_size; i++)
153 		gamma->coeffs[i] = 1.0;
154 
155 	return gamma;
156 }
157 
generate_table_zero(int lut_size)158 static gamma_lut_t *generate_table_zero(int lut_size)
159 {
160 	gamma_lut_t *gamma = alloc_lut(lut_size);
161 	int i;
162 
163 	for (i = 0; i < lut_size; i++)
164 		gamma->coeffs[i] = 0.0;
165 
166 	return gamma;
167 }
168 
coeffs_to_lut(data_t * data,const gamma_lut_t * gamma,uint32_t color_depth,int off)169 static struct drm_color_lut *coeffs_to_lut(data_t *data,
170 					   const gamma_lut_t *gamma,
171 					   uint32_t color_depth,
172 					   int off)
173 {
174 	struct drm_color_lut *lut;
175 	int i, lut_size = gamma->size;
176 	uint32_t max_value = (1 << 16) - 1;
177 	uint32_t mask;
178 
179 	if (is_i915_device(data->drm_fd))
180 		mask = ((1 << color_depth) - 1) << 8;
181 	else
182 		mask = max_value;
183 
184 	lut = malloc(sizeof(struct drm_color_lut) * lut_size);
185 
186 	if (IS_CHERRYVIEW(data->devid))
187 		lut_size -= 1;
188 	for (i = 0; i < lut_size; i++) {
189 		uint32_t v = (gamma->coeffs[i] * max_value);
190 
191 		/*
192 		 * Hardware might encode colors on a different number of bits
193 		 * than what is in our framebuffer (10 or 12bits for example).
194 		 * Mask the lower bits not provided by the framebuffer so we
195 		 * can do CRC comparisons.
196 		 */
197 		v &= mask;
198 
199 		lut[i].red = v;
200 		lut[i].green = v;
201 		lut[i].blue = v;
202 	}
203 
204 	if (IS_CHERRYVIEW(data->devid))
205 		lut[lut_size].red =
206 			lut[lut_size].green =
207 			lut[lut_size].blue = lut[lut_size - 1].red;
208 
209 	return lut;
210 }
211 
set_degamma(data_t * data,igt_pipe_t * pipe,const gamma_lut_t * gamma)212 static void set_degamma(data_t *data,
213 			igt_pipe_t *pipe,
214 			const gamma_lut_t *gamma)
215 {
216 	size_t size = sizeof(struct drm_color_lut) * gamma->size;
217 	struct drm_color_lut *lut = coeffs_to_lut(data, gamma,
218 						  data->color_depth, 0);
219 
220 	igt_pipe_obj_replace_prop_blob(pipe, IGT_CRTC_DEGAMMA_LUT, lut, size);
221 
222 	free(lut);
223 }
224 
set_gamma(data_t * data,igt_pipe_t * pipe,const gamma_lut_t * gamma)225 static void set_gamma(data_t *data,
226 		      igt_pipe_t *pipe,
227 		      const gamma_lut_t *gamma)
228 {
229 	size_t size = sizeof(struct drm_color_lut) * gamma->size;
230 	struct drm_color_lut *lut = coeffs_to_lut(data, gamma,
231 						  data->color_depth, 0);
232 
233 	igt_pipe_obj_replace_prop_blob(pipe, IGT_CRTC_GAMMA_LUT, lut, size);
234 
235 	free(lut);
236 }
237 
set_ctm(igt_pipe_t * pipe,const double * coefficients)238 static void set_ctm(igt_pipe_t *pipe, const double *coefficients)
239 {
240 	struct drm_color_ctm ctm;
241 	int i;
242 
243 	for (i = 0; i < ARRAY_SIZE(ctm.matrix); i++) {
244 		if (coefficients[i] < 0) {
245 			ctm.matrix[i] =
246 				(int64_t) (-coefficients[i] * ((int64_t) 1L << 32));
247 			ctm.matrix[i] |= 1ULL << 63;
248 		} else
249 			ctm.matrix[i] =
250 				(int64_t) (coefficients[i] * ((int64_t) 1L << 32));
251 	}
252 
253 	igt_pipe_obj_replace_prop_blob(pipe, IGT_CRTC_CTM, &ctm, sizeof(ctm));
254 }
255 
disable_prop(igt_pipe_t * pipe,enum igt_atomic_crtc_properties prop)256 static void disable_prop(igt_pipe_t *pipe, enum igt_atomic_crtc_properties prop)
257 {
258 	if (igt_pipe_obj_has_prop(pipe, prop))
259 		igt_pipe_obj_replace_prop_blob(pipe, prop, NULL, 0);
260 }
261 
262 #define disable_degamma(pipe) disable_prop(pipe, IGT_CRTC_DEGAMMA_LUT)
263 #define disable_gamma(pipe) disable_prop(pipe, IGT_CRTC_GAMMA_LUT)
264 #define disable_ctm(pipe) disable_prop(pipe, IGT_CRTC_CTM)
265 
266 /*
267  * Draw 3 gradient rectangles in red, green and blue, with a maxed out
268  * degamma LUT and verify we have the same CRC as drawing solid color
269  * rectangles with linear degamma LUT.
270  */
test_pipe_degamma(data_t * data,igt_plane_t * primary)271 static void test_pipe_degamma(data_t *data,
272 			      igt_plane_t *primary)
273 {
274 	igt_output_t *output;
275 	gamma_lut_t *degamma_linear, *degamma_full;
276 	gamma_lut_t *gamma_linear;
277 	color_t red_green_blue[] = {
278 		{ 1.0, 0.0, 0.0 },
279 		{ 0.0, 1.0, 0.0 },
280 		{ 0.0, 0.0, 1.0 }
281 	};
282 
283 	igt_require(igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_DEGAMMA_LUT));
284 	igt_require(igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_GAMMA_LUT));
285 
286 	degamma_linear = generate_table(data->degamma_lut_size, 1.0);
287 	degamma_full = generate_table_max(data->degamma_lut_size);
288 
289 	gamma_linear = generate_table(data->gamma_lut_size, 1.0);
290 
291 	for_each_valid_output_on_pipe(&data->display, primary->pipe->pipe, output) {
292 		drmModeModeInfo *mode;
293 		struct igt_fb fb_modeset, fb;
294 		igt_crc_t crc_fullgamma, crc_fullcolors;
295 		int fb_id, fb_modeset_id;
296 
297 		igt_output_set_pipe(output, primary->pipe->pipe);
298 		mode = igt_output_get_mode(output);
299 
300 		/* Create a framebuffer at the size of the output. */
301 		fb_id = igt_create_fb(data->drm_fd,
302 				      mode->hdisplay,
303 				      mode->vdisplay,
304 				      DRM_FORMAT_XRGB8888,
305 				      LOCAL_DRM_FORMAT_MOD_NONE,
306 				      &fb);
307 		igt_assert(fb_id);
308 
309 		fb_modeset_id = igt_create_fb(data->drm_fd,
310 					      mode->hdisplay,
311 					      mode->vdisplay,
312 					      DRM_FORMAT_XRGB8888,
313 					      LOCAL_DRM_FORMAT_MOD_NONE,
314 					      &fb_modeset);
315 		igt_assert(fb_modeset_id);
316 
317 		igt_plane_set_fb(primary, &fb_modeset);
318 		disable_ctm(primary->pipe);
319 		disable_degamma(primary->pipe);
320 		set_gamma(data, primary->pipe, gamma_linear);
321 		igt_display_commit(&data->display);
322 
323 		/* Draw solid colors with no degamma transformation. */
324 		paint_rectangles(data, mode, red_green_blue, &fb);
325 		igt_plane_set_fb(primary, &fb);
326 		igt_display_commit(&data->display);
327 		igt_wait_for_vblank(data->drm_fd, primary->pipe->pipe);
328 		igt_pipe_crc_collect_crc(data->pipe_crc, &crc_fullcolors);
329 
330 		/* Draw a gradient with degamma LUT to remap all
331 		 * values to max red/green/blue.
332 		 */
333 		paint_gradient_rectangles(data, mode, red_green_blue, &fb);
334 		igt_plane_set_fb(primary, &fb);
335 		set_degamma(data, primary->pipe, degamma_full);
336 		igt_display_commit(&data->display);
337 		igt_wait_for_vblank(data->drm_fd, primary->pipe->pipe);
338 		igt_pipe_crc_collect_crc(data->pipe_crc, &crc_fullgamma);
339 
340 		/* Verify that the CRC of the software computed output is
341 		 * equal to the CRC of the degamma LUT transformation output.
342 		 */
343 		igt_assert_crc_equal(&crc_fullgamma, &crc_fullcolors);
344 
345 		igt_plane_set_fb(primary, NULL);
346 		igt_output_set_pipe(output, PIPE_NONE);
347 	}
348 
349 	free_lut(degamma_linear);
350 	free_lut(degamma_full);
351 	free_lut(gamma_linear);
352 }
353 
354 /*
355  * Draw 3 gradient rectangles in red, green and blue, with a maxed out gamma
356  * LUT and verify we have the same CRC as drawing solid color rectangles.
357  */
test_pipe_gamma(data_t * data,igt_plane_t * primary)358 static void test_pipe_gamma(data_t *data,
359 			    igt_plane_t *primary)
360 {
361 	igt_output_t *output;
362 	gamma_lut_t *gamma_full;
363 	color_t red_green_blue[] = {
364 		{ 1.0, 0.0, 0.0 },
365 		{ 0.0, 1.0, 0.0 },
366 		{ 0.0, 0.0, 1.0 }
367 	};
368 
369 	igt_require(igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_GAMMA_LUT));
370 
371 	gamma_full = generate_table_max(data->gamma_lut_size);
372 
373 	for_each_valid_output_on_pipe(&data->display, primary->pipe->pipe, output) {
374 		drmModeModeInfo *mode;
375 		struct igt_fb fb_modeset, fb;
376 		igt_crc_t crc_fullgamma, crc_fullcolors;
377 		int fb_id, fb_modeset_id;
378 
379 		igt_output_set_pipe(output, primary->pipe->pipe);
380 		mode = igt_output_get_mode(output);
381 
382 		/* Create a framebuffer at the size of the output. */
383 		fb_id = igt_create_fb(data->drm_fd,
384 				      mode->hdisplay,
385 				      mode->vdisplay,
386 				      DRM_FORMAT_XRGB8888,
387 				      LOCAL_DRM_FORMAT_MOD_NONE,
388 				      &fb);
389 		igt_assert(fb_id);
390 
391 		fb_modeset_id = igt_create_fb(data->drm_fd,
392 					      mode->hdisplay,
393 					      mode->vdisplay,
394 					      DRM_FORMAT_XRGB8888,
395 					      LOCAL_DRM_FORMAT_MOD_NONE,
396 					      &fb_modeset);
397 		igt_assert(fb_modeset_id);
398 
399 		igt_plane_set_fb(primary, &fb_modeset);
400 		disable_ctm(primary->pipe);
401 		disable_degamma(primary->pipe);
402 		set_gamma(data, primary->pipe, gamma_full);
403 		igt_display_commit(&data->display);
404 
405 		/* Draw solid colors with no gamma transformation. */
406 		paint_rectangles(data, mode, red_green_blue, &fb);
407 		igt_plane_set_fb(primary, &fb);
408 		igt_display_commit(&data->display);
409 		igt_wait_for_vblank(data->drm_fd, primary->pipe->pipe);
410 		igt_pipe_crc_collect_crc(data->pipe_crc, &crc_fullcolors);
411 
412 		/* Draw a gradient with gamma LUT to remap all values
413 		 * to max red/green/blue.
414 		 */
415 		paint_gradient_rectangles(data, mode, red_green_blue, &fb);
416 		igt_plane_set_fb(primary, &fb);
417 		igt_display_commit(&data->display);
418 		igt_wait_for_vblank(data->drm_fd, primary->pipe->pipe);
419 		igt_pipe_crc_collect_crc(data->pipe_crc, &crc_fullgamma);
420 
421 		/* Verify that the CRC of the software computed output is
422 		 * equal to the CRC of the gamma LUT transformation output.
423 		 */
424 		igt_assert_crc_equal(&crc_fullgamma, &crc_fullcolors);
425 
426 		igt_plane_set_fb(primary, NULL);
427 		igt_output_set_pipe(output, PIPE_NONE);
428 	}
429 
430 	free_lut(gamma_full);
431 }
432 
433 /*
434  * Draw 3 gradient rectangles in red, green and blue, with a maxed out legacy
435  * gamma LUT and verify we have the same CRC as drawing solid color rectangles
436  * with linear legacy gamma LUT.
437  */
test_pipe_legacy_gamma(data_t * data,igt_plane_t * primary)438 static void test_pipe_legacy_gamma(data_t *data,
439 				   igt_plane_t *primary)
440 {
441 	igt_output_t *output;
442 	color_t red_green_blue[] = {
443 		{ 1.0, 0.0, 0.0 },
444 		{ 0.0, 1.0, 0.0 },
445 		{ 0.0, 0.0, 1.0 }
446 	};
447 	drmModeCrtc *kms_crtc;
448 	uint32_t i, legacy_lut_size;
449 	uint16_t *red_lut, *green_lut, *blue_lut;
450 
451 	kms_crtc = drmModeGetCrtc(data->drm_fd, primary->pipe->crtc_id);
452 	legacy_lut_size = kms_crtc->gamma_size;
453 	drmModeFreeCrtc(kms_crtc);
454 
455 	red_lut = malloc(sizeof(uint16_t) * legacy_lut_size);
456 	green_lut = malloc(sizeof(uint16_t) * legacy_lut_size);
457 	blue_lut = malloc(sizeof(uint16_t) * legacy_lut_size);
458 
459 	for_each_valid_output_on_pipe(&data->display, primary->pipe->pipe, output) {
460 		drmModeModeInfo *mode;
461 		struct igt_fb fb_modeset, fb;
462 		igt_crc_t crc_fullgamma, crc_fullcolors;
463 		int fb_id, fb_modeset_id;
464 
465 		igt_output_set_pipe(output, primary->pipe->pipe);
466 		mode = igt_output_get_mode(output);
467 
468 		/* Create a framebuffer at the size of the output. */
469 		fb_id = igt_create_fb(data->drm_fd,
470 				      mode->hdisplay,
471 				      mode->vdisplay,
472 				      DRM_FORMAT_XRGB8888,
473 				      LOCAL_DRM_FORMAT_MOD_NONE,
474 				      &fb);
475 		igt_assert(fb_id);
476 
477 		fb_modeset_id = igt_create_fb(data->drm_fd,
478 					      mode->hdisplay,
479 					      mode->vdisplay,
480 					      DRM_FORMAT_XRGB8888,
481 					      LOCAL_DRM_FORMAT_MOD_NONE,
482 					      &fb_modeset);
483 		igt_assert(fb_modeset_id);
484 
485 		igt_plane_set_fb(primary, &fb_modeset);
486 		disable_degamma(primary->pipe);
487 		disable_gamma(primary->pipe);
488 		disable_ctm(primary->pipe);
489 		igt_display_commit(&data->display);
490 
491 		/* Draw solid colors with no gamma transformation. */
492 		paint_rectangles(data, mode, red_green_blue, &fb);
493 		igt_plane_set_fb(primary, &fb);
494 		igt_display_commit(&data->display);
495 		igt_wait_for_vblank(data->drm_fd, primary->pipe->pipe);
496 		igt_pipe_crc_collect_crc(data->pipe_crc, &crc_fullcolors);
497 
498 		/* Draw a gradient with gamma LUT to remap all values
499 		 * to max red/green/blue.
500 		 */
501 		paint_gradient_rectangles(data, mode, red_green_blue, &fb);
502 		igt_plane_set_fb(primary, &fb);
503 
504 		red_lut[0] = green_lut[0] = blue_lut[0] = 0;
505 		for (i = 1; i < legacy_lut_size; i++)
506 			red_lut[i] = green_lut[i] = blue_lut[i] = 0xffff;
507 		igt_assert_eq(drmModeCrtcSetGamma(data->drm_fd, primary->pipe->crtc_id,
508 						  legacy_lut_size, red_lut, green_lut, blue_lut), 0);
509 		igt_display_commit(&data->display);
510 		igt_wait_for_vblank(data->drm_fd, primary->pipe->pipe);
511 		igt_pipe_crc_collect_crc(data->pipe_crc, &crc_fullgamma);
512 
513 		/* Verify that the CRC of the software computed output is
514 		 * equal to the CRC of the gamma LUT transformation output.
515 		 */
516 		igt_assert_crc_equal(&crc_fullgamma, &crc_fullcolors);
517 
518 		/* Reset output. */
519 		for (i = 1; i < legacy_lut_size; i++)
520 			red_lut[i] = green_lut[i] = blue_lut[i] = i << 8;
521 
522 		igt_assert_eq(drmModeCrtcSetGamma(data->drm_fd, primary->pipe->crtc_id,
523 						  legacy_lut_size, red_lut, green_lut, blue_lut), 0);
524 		igt_display_commit(&data->display);
525 
526 		igt_plane_set_fb(primary, NULL);
527 		igt_output_set_pipe(output, PIPE_NONE);
528 	}
529 
530 	free(red_lut);
531 	free(green_lut);
532 	free(blue_lut);
533 }
534 
535 static drmModePropertyBlobPtr
get_blob(data_t * data,igt_pipe_t * pipe,enum igt_atomic_crtc_properties prop)536 get_blob(data_t *data, igt_pipe_t *pipe, enum igt_atomic_crtc_properties prop)
537 {
538 	uint64_t prop_value;
539 
540 	prop_value = igt_pipe_obj_get_prop(pipe, prop);
541 
542 	if (prop_value == 0)
543 		return NULL;
544 
545 	return drmModeGetPropertyBlob(data->drm_fd, prop_value);
546 }
547 
548 /*
549  * Verify that setting the legacy gamma LUT resets the gamma LUT set
550  * through the GAMMA_LUT property.
551  */
test_pipe_legacy_gamma_reset(data_t * data,igt_plane_t * primary)552 static void test_pipe_legacy_gamma_reset(data_t *data,
553 					 igt_plane_t *primary)
554 {
555 	const double ctm_identity[] = {
556 		1.0, 0.0, 0.0,
557 		0.0, 1.0, 0.0,
558 		0.0, 0.0, 1.0
559 	};
560 	drmModeCrtc *kms_crtc;
561 	gamma_lut_t *degamma_linear = NULL, *gamma_zero;
562 	uint32_t i, legacy_lut_size;
563 	uint16_t *red_lut, *green_lut, *blue_lut;
564 	struct drm_color_lut *lut;
565 	drmModePropertyBlobPtr blob;
566 	igt_output_t *output;
567 
568 	igt_require(igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_GAMMA_LUT));
569 
570 	if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_DEGAMMA_LUT))
571 		degamma_linear = generate_table(data->degamma_lut_size, 1.0);
572 	gamma_zero = generate_table_zero(data->gamma_lut_size);
573 
574 	for_each_valid_output_on_pipe(&data->display, primary->pipe->pipe, output) {
575 		igt_output_set_pipe(output, primary->pipe->pipe);
576 
577 		/* Ensure we have a clean state to start with. */
578 		disable_degamma(primary->pipe);
579 		disable_ctm(primary->pipe);
580 		disable_gamma(primary->pipe);
581 		igt_display_commit(&data->display);
582 
583 		/* Set a degama & gamma LUT and a CTM using the
584 		 * properties and verify the content of the
585 		 * properties. */
586 		if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_DEGAMMA_LUT))
587 			set_degamma(data, primary->pipe, degamma_linear);
588 		if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_CTM))
589 			set_ctm(primary->pipe, ctm_identity);
590 		set_gamma(data, primary->pipe, gamma_zero);
591 		igt_display_commit(&data->display);
592 
593 		if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_DEGAMMA_LUT)) {
594 			blob = get_blob(data, primary->pipe, IGT_CRTC_DEGAMMA_LUT);
595 			igt_assert(blob &&
596 				   blob->length == (sizeof(struct drm_color_lut) *
597 						    data->degamma_lut_size));
598 			drmModeFreePropertyBlob(blob);
599 		}
600 
601 		if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_CTM)) {
602 			blob = get_blob(data, primary->pipe, IGT_CRTC_CTM);
603 			igt_assert(blob &&
604 				   blob->length == sizeof(struct drm_color_ctm));
605 			drmModeFreePropertyBlob(blob);
606 		}
607 
608 		blob = get_blob(data, primary->pipe, IGT_CRTC_GAMMA_LUT);
609 		igt_assert(blob &&
610 			   blob->length == (sizeof(struct drm_color_lut) *
611 					    data->gamma_lut_size));
612 		lut = (struct drm_color_lut *) blob->data;
613 		for (i = 0; i < data->gamma_lut_size; i++)
614 			igt_assert(lut[i].red == 0 &&
615 				   lut[i].green == 0 &&
616 				   lut[i].blue == 0);
617 		drmModeFreePropertyBlob(blob);
618 
619 		/* Set a gamma LUT using the legacy ioctl and verify
620 		 * the content of the GAMMA_LUT property is changed
621 		 * and that CTM and DEGAMMA_LUT are empty. */
622 		kms_crtc = drmModeGetCrtc(data->drm_fd, primary->pipe->crtc_id);
623 		legacy_lut_size = kms_crtc->gamma_size;
624 		drmModeFreeCrtc(kms_crtc);
625 
626 		red_lut = malloc(sizeof(uint16_t) * legacy_lut_size);
627 		green_lut = malloc(sizeof(uint16_t) * legacy_lut_size);
628 		blue_lut = malloc(sizeof(uint16_t) * legacy_lut_size);
629 
630 		for (i = 0; i < legacy_lut_size; i++)
631 			red_lut[i] = green_lut[i] = blue_lut[i] = 0xffff;
632 
633 		igt_assert_eq(drmModeCrtcSetGamma(data->drm_fd,
634 						  primary->pipe->crtc_id,
635 						  legacy_lut_size,
636 						  red_lut, green_lut, blue_lut),
637 			      0);
638 		igt_display_commit(&data->display);
639 
640 		if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_DEGAMMA_LUT))
641 			igt_assert(get_blob(data, primary->pipe,
642 					    IGT_CRTC_DEGAMMA_LUT) == NULL);
643 
644 		if (igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_CTM))
645 			igt_assert(get_blob(data, primary->pipe, IGT_CRTC_CTM) == NULL);
646 
647 		blob = get_blob(data, primary->pipe, IGT_CRTC_GAMMA_LUT);
648 		igt_assert(blob &&
649 			   blob->length == (sizeof(struct drm_color_lut) *
650 					    legacy_lut_size));
651 		lut = (struct drm_color_lut *) blob->data;
652 		for (i = 0; i < legacy_lut_size; i++)
653 			igt_assert(lut[i].red == 0xffff &&
654 				   lut[i].green == 0xffff &&
655 				   lut[i].blue == 0xffff);
656 		drmModeFreePropertyBlob(blob);
657 
658 		igt_plane_set_fb(primary, NULL);
659 		igt_output_set_pipe(output, PIPE_NONE);
660 	}
661 
662 	free_lut(degamma_linear);
663 	free_lut(gamma_zero);
664 }
665 
crc_equal(igt_crc_t * a,igt_crc_t * b)666 static bool crc_equal(igt_crc_t *a, igt_crc_t *b)
667 {
668   return memcmp(a->crc, b->crc, sizeof(a->crc[0]) * a->n_words) == 0;
669 }
670 
671 /*
672  * Draw 3 rectangles using before colors with the ctm matrix apply and verify
673  * the CRC is equal to using after colors with an identify ctm matrix.
674  */
test_pipe_ctm(data_t * data,igt_plane_t * primary,color_t * before,color_t * after,double * ctm_matrix)675 static bool test_pipe_ctm(data_t *data,
676 			  igt_plane_t *primary,
677 			  color_t *before,
678 			  color_t *after,
679 			  double *ctm_matrix)
680 {
681 	const double ctm_identity[] = {
682 		1.0, 0.0, 0.0,
683 		0.0, 1.0, 0.0,
684 		0.0, 0.0, 1.0
685 	};
686 	gamma_lut_t *degamma_linear, *gamma_linear;
687 	igt_output_t *output;
688 	bool ret = true;
689 
690 	igt_require(igt_pipe_obj_has_prop(primary->pipe, IGT_CRTC_CTM));
691 
692 	degamma_linear = generate_table(data->degamma_lut_size, 1.0);
693 	gamma_linear = generate_table(data->gamma_lut_size, 1.0);
694 
695 	for_each_valid_output_on_pipe(&data->display, primary->pipe->pipe, output) {
696 		drmModeModeInfo *mode;
697 		struct igt_fb fb_modeset, fb;
698 		igt_crc_t crc_software, crc_hardware;
699 		int fb_id, fb_modeset_id;
700 
701 		igt_output_set_pipe(output, primary->pipe->pipe);
702 		mode = igt_output_get_mode(output);
703 
704 		/* Create a framebuffer at the size of the output. */
705 		fb_id = igt_create_fb(data->drm_fd,
706 				      mode->hdisplay,
707 				      mode->vdisplay,
708 				      DRM_FORMAT_XRGB8888,
709 				      LOCAL_DRM_FORMAT_MOD_NONE,
710 				      &fb);
711 		igt_assert(fb_id);
712 
713 		fb_modeset_id = igt_create_fb(data->drm_fd,
714 					      mode->hdisplay,
715 					      mode->vdisplay,
716 					      DRM_FORMAT_XRGB8888,
717 					      LOCAL_DRM_FORMAT_MOD_NONE,
718 					      &fb_modeset);
719 		igt_assert(fb_modeset_id);
720 		igt_plane_set_fb(primary, &fb_modeset);
721 
722 		/*
723 		 * Don't program LUT's for max CTM cases, as limitation of
724 		 * representing intermediate values between 0 and 1.0 causes
725 		 * rounding issues and inaccuracies leading to crc mismatch.
726 		 */
727 		if (memcmp(before, after, sizeof(color_t))) {
728 			set_degamma(data, primary->pipe, degamma_linear);
729 			set_gamma(data, primary->pipe, gamma_linear);
730 		} else {
731 			/* Disable Degamma and Gamma for ctm max test */
732 			disable_degamma(primary->pipe);
733 			disable_gamma(primary->pipe);
734 		}
735 
736 		disable_ctm(primary->pipe);
737 		igt_display_commit(&data->display);
738 
739 		paint_rectangles(data, mode, after, &fb);
740 		igt_plane_set_fb(primary, &fb);
741 		set_ctm(primary->pipe, ctm_identity);
742 		igt_display_commit(&data->display);
743 		igt_wait_for_vblank(data->drm_fd, primary->pipe->pipe);
744 		igt_pipe_crc_collect_crc(data->pipe_crc, &crc_software);
745 
746 		/* With CTM transformation. */
747 		paint_rectangles(data, mode, before, &fb);
748 		igt_plane_set_fb(primary, &fb);
749 		set_ctm(primary->pipe, ctm_matrix);
750 		igt_display_commit(&data->display);
751 		igt_wait_for_vblank(data->drm_fd, primary->pipe->pipe);
752 		igt_pipe_crc_collect_crc(data->pipe_crc, &crc_hardware);
753 
754 		/* Verify that the CRC of the software computed output is
755 		 * equal to the CRC of the CTM matrix transformation output.
756 		 */
757 		ret &= crc_equal(&crc_software, &crc_hardware);
758 
759 		igt_plane_set_fb(primary, NULL);
760 		igt_output_set_pipe(output, PIPE_NONE);
761 	}
762 
763 	free_lut(degamma_linear);
764 	free_lut(gamma_linear);
765 
766 	return ret;
767 }
768 
769 /*
770  * Hardware computes CRC based on the number of bits it is working with (8,
771  * 10, 12, 16 bits), meaning with a framebuffer of 8bits per color will
772  * usually leave the remaining lower bits at 0.
773  *
774  * We're programming the gamma LUT in order to get rid of those lower bits so
775  * we can compare the CRC of a framebuffer without any transformation to a CRC
776  * with transformation applied and verify the CRCs match.
777  *
778  * This test is currently disabled as the CRC computed on Intel hardware seems
779  * to include data on the lower bits, this is preventing us to CRC checks.
780  */
781 #if 0
782 static void test_pipe_limited_range_ctm(data_t *data,
783 					igt_plane_t *primary)
784 {
785 	double limited_result = 235.0 / 255.0;
786 	color_t red_green_blue_limited[] = {
787 		{ limited_result, 0.0, 0.0 },
788 		{ 0.0, limited_result, 0.0 },
789 		{ 0.0, 0.0, limited_result }
790 	};
791 	color_t red_green_blue_full[] = {
792 		{ 0.5, 0.0, 0.0 },
793 		{ 0.0, 0.5, 0.0 },
794 		{ 0.0, 0.0, 0.5 }
795 	};
796 	double ctm[] = { 1.0, 0.0, 0.0,
797 			0.0, 1.0, 0.0,
798 			0.0, 0.0, 1.0 };
799 	gamma_lut_t *degamma_linear, *gamma_linear;
800 	igt_output_t *output;
801 	bool has_broadcast_rgb_output = false;
802 
803 	degamma_linear = generate_table(data->degamma_lut_size, 1.0);
804 	gamma_linear = generate_table(data->gamma_lut_size, 1.0);
805 
806 	for_each_valid_output_on_pipe(&data->display, primary->pipe->pipe, output) {
807 		drmModeModeInfo *mode;
808 		struct igt_fb fb_modeset, fb;
809 		igt_crc_t crc_full, crc_limited;
810 		int fb_id, fb_modeset_id;
811 
812 		if (!igt_output_has_prop(output, IGT_CONNECTOR_BROADCAST_RGB))
813 			continue;
814 
815 		has_broadcast_rgb_output = true;
816 
817 		igt_output_set_pipe(output, primary->pipe->pipe);
818 		mode = igt_output_get_mode(output);
819 
820 		/* Create a framebuffer at the size of the output. */
821 		fb_id = igt_create_fb(data->drm_fd,
822 				      mode->hdisplay,
823 				      mode->vdisplay,
824 				      DRM_FORMAT_XRGB8888,
825 				      LOCAL_DRM_FORMAT_MOD_NONE,
826 				      &fb);
827 		igt_assert(fb_id);
828 
829 		fb_modeset_id = igt_create_fb(data->drm_fd,
830 					      mode->hdisplay,
831 					      mode->vdisplay,
832 					      DRM_FORMAT_XRGB8888,
833 					      LOCAL_DRM_FORMAT_MOD_NONE,
834 					      &fb_modeset);
835 		igt_assert(fb_modeset_id);
836 		igt_plane_set_fb(primary, &fb_modeset);
837 
838 		set_degamma(data, primary->pipe, degamma_linear);
839 		set_gamma(data, primary->pipe, gamma_linear);
840 		set_ctm(primary->pipe, ctm);
841 
842 		igt_output_set_prop_value(output, IGT_CONNECTOR_BROADCAST_RGB, BROADCAST_RGB_FULL);
843 		paint_rectangles(data, mode, red_green_blue_limited, &fb);
844 		igt_plane_set_fb(primary, &fb);
845 		igt_display_commit(&data->display);
846 		igt_wait_for_vblank(data->drm_fd, primary->pipe->pipe);
847 		igt_pipe_crc_collect_crc(data->pipe_crc, &crc_full);
848 
849 		/* Set the output into limited range. */
850 		igt_output_set_prop_value(output, IGT_CONNECTOR_BROADCAST_RGB, BROADCAST_RGB_16_235);
851 		paint_rectangles(data, mode, red_green_blue_full, &fb);
852 		igt_plane_set_fb(primary, &fb);
853 		igt_display_commit(&data->display);
854 		igt_wait_for_vblank(data->drm_fd, primary->pipe->pipe);
855 		igt_pipe_crc_collect_crc(data->pipe_crc, &crc_limited);
856 
857 		/* And reset.. */
858 		igt_output_set_prop_value(output, IGT_CONNECTOR_BROADCAST_RGB, BROADCAST_RGB_FULL);
859 		igt_plane_set_fb(primary, NULL);
860 		igt_output_set_pipe(output, PIPE_NONE);
861 
862 		/* Verify that the CRC of the software computed output is
863 		 * equal to the CRC of the CTM matrix transformation output.
864 		 */
865 		igt_assert_crc_equal(&crc_full, &crc_limited);
866 	}
867 
868 	free_lut(gamma_linear);
869 	free_lut(degamma_linear);
870 
871 	igt_require(has_broadcast_rgb_output);
872 }
873 #endif
874 
875 static void
run_tests_for_pipe(data_t * data,enum pipe p)876 run_tests_for_pipe(data_t *data, enum pipe p)
877 {
878 	igt_pipe_t *pipe;
879 	igt_plane_t *primary;
880 	double delta;
881 	int i;
882 	color_t red_green_blue[] = {
883 		{ 1.0, 0.0, 0.0 },
884 		{ 0.0, 1.0, 0.0 },
885 		{ 0.0, 0.0, 1.0 }
886 	};
887 
888 	igt_fixture {
889 		igt_require_pipe_crc(data->drm_fd);
890 
891 		igt_require(p < data->display.n_pipes);
892 
893 		pipe = &data->display.pipes[p];
894 		igt_require(pipe->n_planes >= 0);
895 
896 		primary = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
897 
898 		data->pipe_crc = igt_pipe_crc_new(data->drm_fd,
899 						  primary->pipe->pipe,
900 						  INTEL_PIPE_CRC_SOURCE_AUTO);
901 
902 		if (igt_pipe_obj_has_prop(&data->display.pipes[p], IGT_CRTC_DEGAMMA_LUT_SIZE)) {
903 			data->degamma_lut_size =
904 				igt_pipe_obj_get_prop(&data->display.pipes[p],
905 						      IGT_CRTC_DEGAMMA_LUT_SIZE);
906 			igt_assert_lt(0, data->degamma_lut_size);
907 		}
908 
909 		if (igt_pipe_obj_has_prop(&data->display.pipes[p], IGT_CRTC_GAMMA_LUT_SIZE)) {
910 			data->gamma_lut_size =
911 				igt_pipe_obj_get_prop(&data->display.pipes[p],
912 						      IGT_CRTC_GAMMA_LUT_SIZE);
913 			igt_assert_lt(0, data->gamma_lut_size);
914 		}
915 
916 		igt_display_require_output_on_pipe(&data->display, p);
917 	}
918 
919 	/* We assume an 8bits depth per color for degamma/gamma LUTs
920 	 * for CRC checks with framebuffer references. */
921 	data->color_depth = 8;
922 	delta = 1.0 / (1 << data->color_depth);
923 
924 	igt_subtest_f("pipe-%s-ctm-red-to-blue", kmstest_pipe_name(p)) {
925 		color_t blue_green_blue[] = {
926 			{ 0.0, 0.0, 1.0 },
927 			{ 0.0, 1.0, 0.0 },
928 			{ 0.0, 0.0, 1.0 }
929 		};
930 		double ctm[] = { 0.0, 0.0, 0.0,
931 				0.0, 1.0, 0.0,
932 				1.0, 0.0, 1.0 };
933 		igt_assert(test_pipe_ctm(data, primary, red_green_blue,
934 					 blue_green_blue, ctm));
935 	}
936 
937 	igt_subtest_f("pipe-%s-ctm-green-to-red", kmstest_pipe_name(p)) {
938 		color_t red_red_blue[] = {
939 			{ 1.0, 0.0, 0.0 },
940 			{ 1.0, 0.0, 0.0 },
941 			{ 0.0, 0.0, 1.0 }
942 		};
943 		double ctm[] = { 1.0, 1.0, 0.0,
944 				0.0, 0.0, 0.0,
945 				0.0, 0.0, 1.0 };
946 		igt_assert(test_pipe_ctm(data, primary, red_green_blue,
947 					 red_red_blue, ctm));
948 	}
949 
950 	igt_subtest_f("pipe-%s-ctm-blue-to-red", kmstest_pipe_name(p)) {
951 		color_t red_green_red[] = {
952 			{ 1.0, 0.0, 0.0 },
953 			{ 0.0, 1.0, 0.0 },
954 			{ 1.0, 0.0, 0.0 }
955 		};
956 		double ctm[] = { 1.0, 0.0, 1.0,
957 				0.0, 1.0, 0.0,
958 				0.0, 0.0, 0.0 };
959 		igt_assert(test_pipe_ctm(data, primary, red_green_blue,
960 					 red_green_red, ctm));
961 	}
962 
963 	/* We tests a few values around the expected result because
964 	 * the it depends on the hardware we're dealing with, we can
965 	 * either get clamped or rounded values and we also need to
966 	 * account for odd number of items in the LUTs. */
967 	igt_subtest_f("pipe-%s-ctm-0-25", kmstest_pipe_name(p)) {
968 		color_t expected_colors[] = {
969 			{ 0.0, }, { 0.0, }, { 0.0, }
970 		};
971 		double ctm[] = { 0.25, 0.0,  0.0,
972 				 0.0,  0.25, 0.0,
973 				 0.0,  0.0,  0.25 };
974 		bool success = false;
975 
976 		for (i = 0; i < 5; i++) {
977 			expected_colors[0].r =
978 				expected_colors[1].g =
979 				expected_colors[2].b =
980 				0.25 + delta * (i - 2);
981 			success |= test_pipe_ctm(data, primary,
982 						 red_green_blue,
983 						 expected_colors, ctm);
984 		}
985 		igt_assert(success);
986 	}
987 
988 	igt_subtest_f("pipe-%s-ctm-0-5", kmstest_pipe_name(p)) {
989 		color_t expected_colors[] = {
990 			{ 0.0, }, { 0.0, }, { 0.0, }
991 		};
992 		double ctm[] = { 0.5, 0.0, 0.0,
993 				 0.0, 0.5, 0.0,
994 				 0.0, 0.0, 0.5 };
995 		bool success = false;
996 
997 		for (i = 0; i < 5; i++) {
998 			expected_colors[0].r =
999 				expected_colors[1].g =
1000 				expected_colors[2].b =
1001 				0.5 + delta * (i - 2);
1002 			success |= test_pipe_ctm(data, primary,
1003 						 red_green_blue,
1004 						 expected_colors, ctm);
1005 		}
1006 		igt_assert(success);
1007 	}
1008 
1009 	igt_subtest_f("pipe-%s-ctm-0-75", kmstest_pipe_name(p)) {
1010 		color_t expected_colors[] = {
1011 			{ 0.0, }, { 0.0, }, { 0.0, }
1012 		};
1013 		double ctm[] = { 0.75, 0.0,  0.0,
1014 				 0.0,  0.75, 0.0,
1015 				 0.0,  0.0,  0.75 };
1016 		bool success = false;
1017 
1018 		for (i = 0; i < 7; i++) {
1019 			expected_colors[0].r =
1020 				expected_colors[1].g =
1021 				expected_colors[2].b =
1022 				0.75 + delta * (i - 3);
1023 			success |= test_pipe_ctm(data, primary,
1024 						 red_green_blue,
1025 						 expected_colors, ctm);
1026 		}
1027 		igt_assert(success);
1028 	}
1029 
1030 	igt_subtest_f("pipe-%s-ctm-max", kmstest_pipe_name(p)) {
1031 		color_t full_rgb[] = {
1032 			{ 1.0, 0.0, 0.0 },
1033 			{ 0.0, 1.0, 0.0 },
1034 			{ 0.0, 0.0, 1.0 }
1035 		};
1036 		double ctm[] = { 100.0,   0.0,   0.0,
1037 				 0.0,   100.0,   0.0,
1038 				 0.0,     0.0, 100.0 };
1039 
1040 		/* CherryView generates values on 10bits that we
1041 		 * produce with an 8 bits per color framebuffer. */
1042 		igt_require(!IS_CHERRYVIEW(data->devid));
1043 
1044 		igt_assert(test_pipe_ctm(data, primary, red_green_blue,
1045 					 full_rgb, ctm));
1046 	}
1047 
1048 	igt_subtest_f("pipe-%s-ctm-negative", kmstest_pipe_name(p)) {
1049 		color_t all_black[] = {
1050 			{ 0.0, 0.0, 0.0 },
1051 			{ 0.0, 0.0, 0.0 },
1052 			{ 0.0, 0.0, 0.0 }
1053 		};
1054 		double ctm[] = { -1.0,  0.0,  0.0,
1055 				 0.0, -1.0,  0.0,
1056 				 0.0,  0.0, -1.0 };
1057 		igt_assert(test_pipe_ctm(data, primary, red_green_blue,
1058 					 all_black, ctm));
1059 	}
1060 
1061 #if 0
1062 	igt_subtest_f("pipe-%s-ctm-limited-range", kmstest_pipe_name(p))
1063 		test_pipe_limited_range_ctm(data, primary);
1064 #endif
1065 
1066 	igt_subtest_f("pipe-%s-degamma", kmstest_pipe_name(p))
1067 		test_pipe_degamma(data, primary);
1068 
1069 	igt_subtest_f("pipe-%s-gamma", kmstest_pipe_name(p))
1070 		test_pipe_gamma(data, primary);
1071 
1072 	igt_subtest_f("pipe-%s-legacy-gamma", kmstest_pipe_name(p))
1073 		test_pipe_legacy_gamma(data, primary);
1074 
1075 	igt_subtest_f("pipe-%s-legacy-gamma-reset", kmstest_pipe_name(p))
1076 		test_pipe_legacy_gamma_reset(data, primary);
1077 
1078 	igt_fixture {
1079 		disable_degamma(primary->pipe);
1080 		disable_gamma(primary->pipe);
1081 		disable_ctm(primary->pipe);
1082 		igt_display_commit(&data->display);
1083 
1084 		igt_pipe_crc_free(data->pipe_crc);
1085 		data->pipe_crc = NULL;
1086 	}
1087 }
1088 
1089 static int
pipe_set_property_blob_id(igt_pipe_t * pipe,enum igt_atomic_crtc_properties prop,uint32_t blob_id)1090 pipe_set_property_blob_id(igt_pipe_t *pipe, enum igt_atomic_crtc_properties prop, uint32_t blob_id)
1091 {
1092 	int ret;
1093 
1094 	igt_pipe_obj_replace_prop_blob(pipe, prop, NULL, 0);
1095 
1096 	igt_pipe_obj_set_prop_value(pipe, prop, blob_id);
1097 
1098 	ret = igt_display_try_commit2(pipe->display, pipe->display->is_atomic ? COMMIT_ATOMIC : COMMIT_LEGACY);
1099 
1100 	igt_pipe_obj_set_prop_value(pipe, prop, 0);
1101 
1102 	return ret;
1103 }
1104 
1105 static int
pipe_set_property_blob(igt_pipe_t * pipe,enum igt_atomic_crtc_properties prop,void * ptr,size_t length)1106 pipe_set_property_blob(igt_pipe_t *pipe, enum igt_atomic_crtc_properties prop, void *ptr, size_t length)
1107 {
1108 	igt_pipe_obj_replace_prop_blob(pipe, prop, ptr, length);
1109 
1110 	return igt_display_try_commit2(pipe->display, pipe->display->is_atomic ? COMMIT_ATOMIC : COMMIT_LEGACY);
1111 }
1112 
1113 static void
invalid_gamma_lut_sizes(data_t * data)1114 invalid_gamma_lut_sizes(data_t *data)
1115 {
1116 	igt_display_t *display = &data->display;
1117 	igt_pipe_t *pipe = &display->pipes[0];
1118 	size_t gamma_lut_size = data->gamma_lut_size * sizeof(struct drm_color_lut);
1119 	struct drm_color_lut *gamma_lut;
1120 
1121 	igt_require(igt_pipe_obj_has_prop(pipe, IGT_CRTC_GAMMA_LUT));
1122 
1123 	gamma_lut = malloc(gamma_lut_size * 2);
1124 
1125 	igt_display_commit2(display, display->is_atomic ? COMMIT_ATOMIC : COMMIT_LEGACY);
1126 
1127 	igt_assert_eq(pipe_set_property_blob(pipe, IGT_CRTC_GAMMA_LUT,
1128 					     gamma_lut, 1),
1129 		      -EINVAL);
1130 	igt_assert_eq(pipe_set_property_blob(pipe, IGT_CRTC_GAMMA_LUT,
1131 					     gamma_lut, gamma_lut_size + 1),
1132 		      -EINVAL);
1133 	igt_assert_eq(pipe_set_property_blob(pipe, IGT_CRTC_GAMMA_LUT,
1134 					     gamma_lut, gamma_lut_size - 1),
1135 		      -EINVAL);
1136 	igt_assert_eq(pipe_set_property_blob(pipe, IGT_CRTC_GAMMA_LUT,
1137 					     gamma_lut, gamma_lut_size + sizeof(struct drm_color_lut)),
1138 		      -EINVAL);
1139 	igt_assert_eq(pipe_set_property_blob_id(pipe, IGT_CRTC_GAMMA_LUT, pipe->crtc_id),
1140 		      -EINVAL);
1141 	igt_assert_eq(pipe_set_property_blob_id(pipe, IGT_CRTC_GAMMA_LUT, 4096 * 4096),
1142 		      -EINVAL);
1143 
1144 	free(gamma_lut);
1145 }
1146 
1147 static void
invalid_degamma_lut_sizes(data_t * data)1148 invalid_degamma_lut_sizes(data_t *data)
1149 {
1150 	igt_display_t *display = &data->display;
1151 	igt_pipe_t *pipe = &display->pipes[0];
1152 	size_t degamma_lut_size = data->degamma_lut_size * sizeof(struct drm_color_lut);
1153 	struct drm_color_lut *degamma_lut;
1154 
1155 	igt_require(igt_pipe_obj_has_prop(pipe, IGT_CRTC_DEGAMMA_LUT));
1156 
1157 	degamma_lut = malloc(degamma_lut_size * 2);
1158 
1159 	igt_display_commit2(display, display->is_atomic ? COMMIT_ATOMIC : COMMIT_LEGACY);
1160 
1161 	igt_assert_eq(pipe_set_property_blob(pipe, IGT_CRTC_DEGAMMA_LUT,
1162 					     degamma_lut, 1), -EINVAL);
1163 	igt_assert_eq(pipe_set_property_blob(pipe, IGT_CRTC_DEGAMMA_LUT,
1164 					     degamma_lut, degamma_lut_size + 1),
1165 		      -EINVAL);
1166 	igt_assert_eq(pipe_set_property_blob(pipe, IGT_CRTC_DEGAMMA_LUT,
1167 					     degamma_lut, degamma_lut_size - 1),
1168 		      -EINVAL);
1169 	igt_assert_eq(pipe_set_property_blob(pipe, IGT_CRTC_DEGAMMA_LUT,
1170 					     degamma_lut, degamma_lut_size + sizeof(struct drm_color_lut)),
1171 		      -EINVAL);
1172 	igt_assert_eq(pipe_set_property_blob_id(pipe, IGT_CRTC_DEGAMMA_LUT, pipe->crtc_id),
1173 		      -EINVAL);
1174 	igt_assert_eq(pipe_set_property_blob_id(pipe, IGT_CRTC_DEGAMMA_LUT, 4096 * 4096),
1175 		      -EINVAL);
1176 
1177 	free(degamma_lut);
1178 }
1179 
1180 static void
invalid_ctm_matrix_sizes(data_t * data)1181 invalid_ctm_matrix_sizes(data_t *data)
1182 {
1183 	igt_display_t *display = &data->display;
1184 	igt_pipe_t *pipe = &display->pipes[0];
1185 	void *ptr;
1186 
1187 	igt_require(igt_pipe_obj_has_prop(pipe, IGT_CRTC_CTM));
1188 
1189 	ptr = malloc(sizeof(struct drm_color_ctm) * 4);
1190 
1191 	igt_assert_eq(pipe_set_property_blob(pipe, IGT_CRTC_CTM, ptr, 1),
1192 		      -EINVAL);
1193 	igt_assert_eq(pipe_set_property_blob(pipe, IGT_CRTC_CTM, ptr,
1194 					     sizeof(struct drm_color_ctm) + 1),
1195 		      -EINVAL);
1196 	igt_assert_eq(pipe_set_property_blob(pipe, IGT_CRTC_CTM, ptr,
1197 					     sizeof(struct drm_color_ctm) - 1),
1198 		      -EINVAL);
1199 	igt_assert_eq(pipe_set_property_blob(pipe, IGT_CRTC_CTM, ptr,
1200 					     sizeof(struct drm_color_ctm) * 2),
1201 		      -EINVAL);
1202 	igt_assert_eq(pipe_set_property_blob_id(pipe, IGT_CRTC_CTM, pipe->crtc_id),
1203 		      -EINVAL);
1204 	igt_assert_eq(pipe_set_property_blob_id(pipe, IGT_CRTC_CTM, 4096 * 4096),
1205 		      -EINVAL);
1206 
1207 	free(ptr);
1208 }
1209 
1210 igt_main
1211 {
1212 	data_t data = {};
1213 	enum pipe pipe;
1214 
1215 	igt_skip_on_simulation();
1216 
1217 	igt_fixture {
1218 		data.drm_fd = drm_open_driver_master(DRIVER_INTEL | DRIVER_AMDGPU);
1219 		if (is_i915_device(data.drm_fd))
1220 			data.devid = intel_get_drm_devid(data.drm_fd);
1221 		kmstest_set_vt_graphics_mode();
1222 
1223 		igt_display_require(&data.display, data.drm_fd);
1224 	}
1225 
1226 	for_each_pipe_static(pipe)
1227 		igt_subtest_group
1228 			run_tests_for_pipe(&data, pipe);
1229 
1230 	igt_subtest_f("pipe-invalid-gamma-lut-sizes")
1231 		invalid_gamma_lut_sizes(&data);
1232 
1233 	igt_subtest_f("pipe-invalid-degamma-lut-sizes")
1234 		invalid_degamma_lut_sizes(&data);
1235 
1236 	igt_subtest_f("pipe-invalid-ctm-matrix-sizes")
1237 		invalid_ctm_matrix_sizes(&data);
1238 
1239 	igt_fixture {
1240 		igt_display_fini(&data.display);
1241 	}
1242 }
1243