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