From patchwork Tue Jan 5 10:06:30 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Dhanya Pillai X-Patchwork-Id: 7953541 Return-Path: X-Original-To: patchwork-intel-gfx@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 11AAE9F3E6 for ; Tue, 5 Jan 2016 10:05:01 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id B903D2015E for ; Tue, 5 Jan 2016 10:04:58 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 6950F2013A for ; Tue, 5 Jan 2016 10:04:56 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 81B686E182; Tue, 5 Jan 2016 02:04:55 -0800 (PST) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by gabe.freedesktop.org (Postfix) with ESMTP id C5D106E171 for ; Tue, 5 Jan 2016 02:04:53 -0800 (PST) Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga103.jf.intel.com with ESMTP; 05 Jan 2016 02:04:53 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.20,524,1444719600"; d="scan'208";a="628258142" Received: from dhanyapr-2012-client-platform.iind.intel.com ([10.223.26.113]) by FMSMGA003.fm.intel.com with ESMTP; 05 Jan 2016 02:04:50 -0800 From: Dhanya Pillai To: intel-gfx@lists.freedesktop.org Date: Tue, 5 Jan 2016 15:36:30 +0530 Message-Id: <1451988390-8306-1-git-send-email-dhanya.p.r@intel.com> X-Mailer: git-send-email 1.9.1 MIME-Version: 1.0 Cc: Dhanya , jesse.barnes@intel.com Subject: [Intel-gfx] [PATCH i-g-t] tests/kms_color:Color i-g-t X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Dhanya This patch will verify color correction capability of a display driver. Gamma/CSC/De-gamma for BDW/SKL/BXT and CHT supported. Signed-off-by: Dhanya --- tests/.gitignore | 1 + tests/Makefile.sources | 1 + tests/kms_color.c | 1014 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1016 insertions(+) create mode 100644 tests/kms_color.c diff --git a/tests/.gitignore b/tests/.gitignore index 7f20f2b..6fc4782 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -130,6 +130,7 @@ gen7_forcewake_mt kms_3d kms_addfb_basic kms_atomic +kms_color kms_crtc_background_color kms_cursor_crc kms_draw_crc diff --git a/tests/Makefile.sources b/tests/Makefile.sources index d594038..f2af648 100644 --- a/tests/Makefile.sources +++ b/tests/Makefile.sources @@ -68,6 +68,7 @@ TESTS_progs_M = \ gem_write_read_ring_switch \ kms_addfb_basic \ kms_atomic \ + kms_color \ kms_cursor_crc \ kms_draw_crc \ kms_fbc_crc \ diff --git a/tests/kms_color.c b/tests/kms_color.c new file mode 100644 index 0000000..dd3c2fb --- /dev/null +++ b/tests/kms_color.c @@ -0,0 +1,1014 @@ +/* + * Copyright © 2015 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * Authors: + * Dhanya Pillai + */ + +#include +#include +#include +#include +#include +#include "drmtest.h" +#include "drm.h" +#include "igt_debugfs.h" +#include "igt_kms.h" +#include "igt_core.h" +#include "intel_io.h" +#include "intel_chipset.h" +#include "igt_aux.h" + + +IGT_TEST_DESCRIPTION("Test Color Features at Pipe level"); +/* + +This tool tests the following color features: + CTM, GAMMA(8/10/12/split/legacy) and De-gamma. +Few negative test cases are also included + +Tests willl enable one primary and one sprite plane and apply +the specific color feature and do the verification by CRC checks. +*/ + +#define CSC_MAX_VALS 9 +#define BDW_SPLITGAMMA_MAX_VALS 512 +#define BDW_8BIT_GAMMA_MAX_VALS 256 +#define BDW_10BIT_GAMMA_MAX_VALS 1024 +#define BDW_12BIT_GAMMA_MAX_VALS 513 +#define BDW_MAX_GAMMA ((1 << 24) - 1) +#define BDW_MIN_GAMMA 0 + +#define RED_FB 0 +#define GREEN_FB 1 +#define BLUE_FB 2 + +#ifndef drm_r32g32b32 +struct drm_r32g32b32 { + __u32 r32; + __u32 g32; + __u32 b32; + __u32 reserved; +}; +#endif +#ifndef drm_palette +struct drm_palette { + struct drm_r32g32b32 lut[0]; +}; +#endif +#ifndef drm_ctm + struct drm_ctm { + __s64 ctm_coeff[9]; +}; +#endif +#ifndef drm_palette_caps +struct drm_palette_caps { + __u32 version; + __u32 reserved; + __u32 num_samples_before_ctm; + __u32 num_samples_after_ctm; +}; +#endif + +enum ctm_color { + RED, + GREEN, + BLUE, + REVERSE, + NEGATIVE, + FRACTION +}; + +enum blob { + INVALID_BLOB_ID, + INVALID_BLOB_DATA, + INVALID_BLOB_LENGTH, + INVALID_BLOB_ID_SMALL, + INVALID_BLOB_NULL +}; + +enum color_property { + ctm_property, + legacy_gamma, + gamma_property_8bit, + gamma_property_10bit, + gamma_property_12bit, + gamma_property_split +}; +static const float ctm_red[9] = {1, 1, 1, 0, 0, 0, 0, 0, 0}; +static const float ctm_green[9] = {0, 0, 0, 1, 1, 1, 0, 0, 0}; +static const float ctm_blue[9] = {0, 0, 0, 0, 0, 0, 1, 1, 1}; +static const float ctm_identity[9] = {1, 0, 0, 0, 1, 0, 0, 0, 1}; +static const float ctm_reverse[9] = {0, 0, 1, 0, 1, 0, 1, 0, 0}; +static const float ctm_negative[9] = {-1, -1, -1, -1, -1, -1, -1, -1, -1}; +static const float ctm_fraction[9] = {1234567.7652, 0.12334, 0.9898989, 0.45454545, 0.12121212, 0.232323, 3.98768, 0.00000, 1.22345}; + + +struct framebuffer_color { + int red; + int green; + int blue; +}; +struct framebuffer_color fb_color = { 0, 0, 0}; + + +struct data_t { + int fb_initial; + int drm_fd; + int gen; + int w, h; + igt_display_t display; + struct igt_fb fb_prep; + struct igt_fb fb, fb1; + igt_pipe_crc_t *pipe_crc; + enum pipe pipe; + +}; + + +static int create_blob(int fd, uint64_t *data, int length) +{ + struct drm_mode_create_blob blob; + int ret = -1; + + blob.data = (uint64_t)data; + blob.length = length; + blob.blob_id = -1; + ret = ioctl(fd, DRM_IOCTL_MODE_CREATEPROPBLOB, &blob); + if (!ret) + return blob.blob_id; + igt_fail(IGT_EXIT_FAILURE); + return ret; +} + +static void prepare_crtc(struct data_t *data, igt_output_t *output, + enum pipe pipe1, igt_plane_t *plane, drmModeModeInfo *mode, + enum igt_commit_style s) +{ + igt_display_t *display = &data->display; + + igt_output_set_pipe(output, pipe1); + igt_pipe_crc_free(data->pipe_crc); + data->pipe_crc = igt_pipe_crc_new(pipe1, INTEL_PIPE_CRC_SOURCE_AUTO); + /* allocate fb for plane 1 */ + data->fb_initial = igt_create_color_fb(data->drm_fd, + mode->hdisplay, mode->vdisplay, + DRM_FORMAT_XRGB8888, + LOCAL_I915_FORMAT_MOD_X_TILED, /* tiled */ + fb_color.red, fb_color.green, fb_color.blue, + &data->fb_prep); + igt_assert(data->fb_initial); + + igt_plane_set_fb(plane, &data->fb_prep); + + igt_display_commit2(display, s); +} + +static void cleanup_crtc(struct data_t *data, igt_output_t *output, + igt_plane_t *plane) +{ + igt_display_t *display = &data->display; + if (data->fb_prep.fb_id) { + igt_remove_fb(data->drm_fd, &data->fb_prep); + data->fb_initial = 0; + } + if (data->fb.fb_id) + igt_remove_fb(data->drm_fd, &data->fb); + if (!plane->is_primary) { + igt_plane_t *primary; + primary = igt_output_get_plane(output, IGT_PLANE_PRIMARY); + igt_plane_set_fb(primary, NULL); + } + igt_plane_set_fb(plane, NULL); + igt_output_set_pipe(output, PIPE_ANY); + igt_display_commit2(display, COMMIT_UNIVERSAL); + +} + +static int get_color_property(int drm_fd, int id, int object, const char *prop_name) + +{ + int i = 0, ret = 0; + int blob_id = -1; + drmModeObjectPropertiesPtr props = NULL; + igt_fail_on_f(id < 0 || ((object != DRM_MODE_OBJECT_CRTC) && + (object != DRM_MODE_OBJECT_PLANE)), "Invalid input to get color property %d", id); + + props = drmModeObjectGetProperties(drm_fd, id, object); + igt_fail_on_f(!props, "\nNo property for object id=%d\n", id); + for (i = 0; i < props->count_props; i++) { + drmModePropertyPtr prop = drmModeGetProperty(drm_fd, + props->props[i]); + if (strcmp(prop->name, prop_name) == 0) { + blob_id = props->prop_values[i]; + + break; + } + drmModeFreeProperty(prop); + } + ret = blob_id; + drmModeFreeObjectProperties(props); + igt_fail_on_f(i == props->count_props, "%s No such property\n", prop_name); + return ret; +} + + +static int set_color_property(int drm_fd, int id, int object, const char *prop_name, int blob_id) +{ + int i = 0, res = -1; + + drmModeObjectPropertiesPtr props = NULL; + igt_fail_on_f(id < 0 || ((object != DRM_MODE_OBJECT_CRTC) && + (object != DRM_MODE_OBJECT_PLANE)), "Invalid input to get color property %d", id); + + + props = drmModeObjectGetProperties(drm_fd, id, object); + igt_fail_on_f(!props, "\nNo property for object id=%d\n", id); + for (i = 0; i < props->count_props; i++) { + drmModePropertyPtr prop = drmModeGetProperty(drm_fd, + props->props[i]); + if (strcmp(prop->name, prop_name) == 0) { + res = drmModeObjectSetProperty(drm_fd, id, object, + (uint32_t)prop->prop_id, blob_id); + + if (res) { + drmModeFreeProperty(prop); + } else { + drmModeFreeProperty(prop); + break; + } + } + + } + drmModeFreeObjectProperties(props); + igt_fail_on_f(i == props->count_props, "%s No such property\n", prop_name); + return res; +} + +static int64_t convertFloatToBinary(double input) +{ + + int integer_part, count = 0; + uint32_t temp_ip, frac_val = 0x00000000; + uint64_t integer_val = 0x00000000; + int64_t value = 0x0000000000000000; + float fractional_part, ip; + integer_part = (int)input; + fractional_part = input - integer_part; + while (fractional_part != 0.000000) { + ip = fractional_part * 16; + temp_ip = (int)(fractional_part * 16); + frac_val = frac_val | (temp_ip << (28 - count * 4)); + count++; + fractional_part = ip - temp_ip; + } + integer_val = integer_part; + value = value | ((integer_val) * ((int64_t)1L << 32)); + value = value | frac_val; + return value; + + +} + +static void write_gamma_lut(uint32_t num_samples, struct drm_r32g32b32 *gamma_ptr, int unit_gamma) +{ + unsigned short Red, Green, Blue; + uint32_t r32, b32, g32; + uint64_t i; + + for (i = 0; i < num_samples; i++) { + if (unit_gamma == 0) { + Blue = BDW_MAX_GAMMA; + Green = BDW_MAX_GAMMA; + Red = BDW_MAX_GAMMA; + } else { + Blue = BDW_MIN_GAMMA; + Green = BDW_MIN_GAMMA; + Red = BDW_MIN_GAMMA; + } + r32 = Red; + g32 = Green; + b32 = Blue; + r32 <<= 8; + g32 <<= 8; + b32 <<= 8; + gamma_ptr[i].r32 = r32; + gamma_ptr[i].g32 = g32; + gamma_ptr[i].b32 = b32; + } +} + +static uint64_t get_blob(int fd, int blob_id, int length) +{ + struct drm_mode_get_blob blob; + int ret = 0; + + blob.blob_id = blob_id; + blob.length = length; + blob.data = (uint64_t)malloc(blob.length); + ret = ioctl(fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob); + + if (ret) + igt_info("GET BLOB Failed\n"); + + return blob.data; +} + +static void enable_plane(struct data_t *data, igt_display_t *display, igt_output_t *output, int pipe1) +{ + enum igt_commit_style commit; + enum pipe pipe2; + int width, height; + uint32_t pixelformat = DRM_FORMAT_XRGB8888; + igt_plane_t *plane; + + commit = COMMIT_UNIVERSAL; + + for_each_connected_output(display, output) { + drmModeModeInfo *mode; + pipe2 = output->config.pipe; + + if (pipe2 != pipe1) + continue; + igt_output_set_pipe(output, pipe2); + mode = igt_output_get_mode(output); + /*Draw the initial primary plane*/ + plane = igt_output_get_plane(output, IGT_PLANE_PRIMARY); + + prepare_crtc(data, output, pipe2, plane, mode, commit); + /*Random Size Buffer Creation */ + width = 600; + height = 600; + + plane = igt_output_get_plane(output, IGT_PLANE_2); + igt_create_color_fb(data->drm_fd, + width, height, + pixelformat, + LOCAL_DRM_FORMAT_MOD_NONE, + fb_color.red, fb_color.green, fb_color.blue, + &data->fb); + igt_plane_set_position(plane, 100, 100); + + igt_plane_set_fb(plane, &data->fb); + igt_display_commit2(display, commit); + } + +} + +static void apply_ctm(igt_display_t *display, igt_output_t *output, const float *ctm) +{ + int res, i, blob_id; + uint64_t blob_address; + struct drm_ctm *ctm_data = NULL; + ctm_data = (struct drm_ctm *) + malloc(sizeof(struct drm_ctm)); + + for (i = 0; i < CSC_MAX_VALS; i++) { + ctm_data->ctm_coeff[i] = convertFloatToBinary(*(ctm + i)); + } + + blob_id = create_blob(display->drm_fd, + (int *)(ctm_data), sizeof(struct drm_ctm)); + igt_fail_on_f (blob_id < 0, "CTM:BLOB IOCTL Fail\n"); + res = set_color_property(display->drm_fd, output->config.crtc->crtc_id, + DRM_MODE_OBJECT_CRTC, "CTM", blob_id); + igt_fail_on_f (res < 0, "CTM:Set Property Failed\n"); + res = get_color_property(display->drm_fd, output->config.crtc->crtc_id, DRM_MODE_OBJECT_CRTC, "CTM"); + igt_fail_on_f (res < 0, "CTM:Get Property Failed\n"); + blob_address = get_blob(display->drm_fd, res, sizeof(struct drm_ctm)); + ctm_data = (struct drm_ctm *) (intptr_t) blob_address; + +} + +static void test_pipe_ctm_invalid_tests(struct data_t *data, enum blob op) +{ + + int res, i, length; + struct drm_ctm *ctm_data = NULL; + struct drm_mode_create_blob blob; + struct drm_mode_create_blob empty_blob; + enum pipe pipe1; + int ret = -1; + struct drm_ctm *invalid_ctm_data = NULL; + igt_display_t *display = &data->display; + igt_output_t *output; + + ctm_data = (struct drm_ctm *)malloc(sizeof(struct drm_ctm)); + for (i = 0; i < CSC_MAX_VALS; i++) { + ctm_data->ctm_coeff[i] = 1L; + } + + length = sizeof(struct drm_ctm); + blob.data = (uint64_t)ctm_data; + blob.length = length; + blob.blob_id = -1; + + if (op == INVALID_BLOB_LENGTH) + blob.length = 10; + ret = ioctl(display->drm_fd, DRM_IOCTL_MODE_CREATEPROPBLOB, &blob); + igt_fail_on_f (ret < 0, "GAMMA:BLOB IOCTL Fail\n"); + + if (op == INVALID_BLOB_ID) + blob.blob_id = 4096*4096; + if (op == INVALID_BLOB_NULL) + blob = empty_blob; + for_each_connected_output(display, output) { + pipe1 = output->config.pipe; + igt_output_set_pipe(output, pipe1); + + res = set_color_property(display->drm_fd, output->config.crtc->crtc_id, + DRM_MODE_OBJECT_CRTC, "CTM", blob.blob_id); + free(ctm_data); + free(invalid_ctm_data); + igt_fail_on_f (res >= 0, "CTM:Invalid Tests Failed %d\n", res); + } + +} +static void test_pipe_ctm_fraction(struct data_t *data, igt_display_t *display, igt_output_t *output, + enum ctm_color value, int pipe1) +{ + + /*Enable red planes */ + fb_color.red = 1; + fb_color.green = 0; + fb_color.blue = 0; + enable_plane(data, display, output, pipe1); + + /*Apply fractional ctm*/ + apply_ctm(display, output, ctm_fraction); + enable_plane(data, display, output, pipe1); + /*Restore Identity Matrix*/ + apply_ctm(display, output, ctm_identity); + enable_plane(data, display, output, pipe1); + + +} + +static void test_pipe_ctm_negative(struct data_t *data, igt_display_t *display, igt_output_t *output, + enum ctm_color value, int pipe1) +{ + + /*Enable red planes */ + fb_color.red = 1; + fb_color.green = 0; + fb_color.blue = 0; + enable_plane(data, display, output, pipe1); + + /*Apply negative ctm*/ + apply_ctm(display, output, ctm_negative); + enable_plane(data, display, output, pipe1); + + /*Restoring Identity matrix*/ + apply_ctm(display, output, ctm_identity); + enable_plane(data, display, output, pipe1); + +} + +static void test_pipe_ctm_reverse(struct data_t *data, igt_display_t *display, igt_output_t *output, + enum ctm_color value, int pipe1) +{ + igt_crc_t crc_reference_red, crc_reference_blue; + igt_crc_t crc_reverse_red, crc_reverse_blue, crc_identity_red, crc_identity_blue; + + /*Enable red planes and capture reference crc*/ + fb_color.red = 1; + fb_color.green = 0; + fb_color.blue = 0; + enable_plane(data, display, output, pipe1); + igt_pipe_crc_collect_crc(data->pipe_crc, &crc_reference_red); + /*Apply reverse ctm matrix on red plane*/ + apply_ctm(display, output, ctm_reverse); + enable_plane(data, display, output, pipe1); + igt_pipe_crc_collect_crc(data->pipe_crc, &crc_reverse_red); + + /*Apply identity ctm matrix on red plane*/ + apply_ctm(display, output, ctm_identity); + enable_plane(data, display, output, pipe1); + igt_pipe_crc_collect_crc(data->pipe_crc, &crc_identity_red); + + /*Enable blue planes and capture reference crc*/ + fb_color.red = 0; + fb_color.green = 0; + fb_color.blue = 1; + + enable_plane(data, display, output, pipe1); + igt_pipe_crc_collect_crc(data->pipe_crc, &crc_reference_blue); + + /*Apply reverse ctm matrix on blue plane*/ + apply_ctm(display, output, ctm_reverse); + enable_plane(data, display, output, pipe1); + igt_pipe_crc_collect_crc(data->pipe_crc, &crc_reverse_blue); + + /*Apply identity ctm matrix on blue plane*/ + apply_ctm(display, output, ctm_identity); + enable_plane(data, display, output, pipe1); + igt_pipe_crc_collect_crc(data->pipe_crc, &crc_identity_blue); + + /*Compare crc*/ + + igt_assert_crc_equal(&crc_reference_red, &crc_identity_red); + igt_assert_crc_equal(&crc_reference_blue, &crc_identity_blue); + igt_assert_crc_equal(&crc_reverse_blue, &crc_identity_red); + igt_assert_crc_equal(&crc_reverse_red, &crc_identity_blue); + /*Restoring Identity Matrix*/ + apply_ctm(display, output, ctm_identity); + enable_plane(data, display, output, pipe1); +} + +/* +This function verify ctm feature using both CRC check. +Steps followed are: +1.Enable plane for capturing reference CRC +2.Capture Reference CRC +3.Apply CSC on Pipe +4.Enable Plane .CSC will be applied on this planes. +5.Capture CRC and compare with reference CRC +6. Register Validation for CRC +*/ + +static void test_pipe_ctm(struct data_t *data, igt_display_t *display, igt_output_t *output, + enum ctm_color value, int pipe1) +{ + + const float *ctm; + igt_crc_t crc_current, crc_reference, crc_reference_white; + fb_color.red = 1; + fb_color.green = 1; + fb_color.blue = 1; + + switch (value) { + case RED: + ctm = ctm_red; + fb_color.red = 1; + fb_color.green = 0; + fb_color.blue = 0; + break; + case GREEN: + ctm = ctm_green; + fb_color.red = 0; + fb_color.green = 1; + fb_color.blue = 0; + break; + case BLUE: + ctm = ctm_blue; + fb_color.red = 0; + fb_color.green = 0; + fb_color.blue = 1; + + break; + default: + ctm = ctm_identity; + break; + } + + /*Enable planes and capture reference crc*/ + enable_plane(data, display, output, pipe1); + igt_pipe_crc_collect_crc(data->pipe_crc, &crc_reference); + + /*White Plane Enabling*/ + fb_color.red = 1; + fb_color.green = 1; + fb_color.blue = 1; + + enable_plane(data, display, output, pipe1); + igt_pipe_crc_collect_crc(data->pipe_crc, &crc_reference_white); + + /*Apply CSC*/ + apply_ctm(display, output, ctm); + enable_plane(data, display, output, pipe1); + igt_pipe_crc_collect_crc(data->pipe_crc, &crc_current); + igt_assert_crc_equal(&crc_reference, &crc_current); + + /*Restoring the Unit CSC*/ + apply_ctm(display, output, ctm_identity); + enable_plane(data, display, output, pipe1); + igt_pipe_crc_collect_crc(data->pipe_crc, &crc_current); + igt_assert_crc_equal(&crc_reference_white, &crc_current); +} + +static void apply_gamma(struct data_t *data, igt_display_t *display, igt_output_t *output, uint32_t num_samples, int unit_gamma) +{ + struct drm_palette *gamma_data = NULL; + struct drm_palette *degamma_data = NULL; + int ret, res, blob_id_gamma, blob_length_gamma; + int blob_id_degamma, blob_length_degamma; + uint64_t num_samples_gamma, num_samples_degamma; + num_samples_gamma = num_samples; + + if (num_samples == BDW_SPLITGAMMA_MAX_VALS) { + + kmstest_get_property(display->drm_fd, output->config.crtc->crtc_id, DRM_MODE_OBJECT_CRTC, "COEFFICIENTS_BEFORE_CTM", NULL, &num_samples_degamma, NULL); + kmstest_get_property(display->drm_fd, output->config.crtc->crtc_id, DRM_MODE_OBJECT_CRTC, "COEFFICIENTS_AFTER_CTM", NULL, &num_samples_gamma, NULL); + + blob_length_degamma = (sizeof(struct drm_palette) + (num_samples_degamma * sizeof(struct drm_r32g32b32))); + degamma_data = malloc(blob_length_degamma); + write_gamma_lut(num_samples_degamma, degamma_data->lut, unit_gamma); + blob_id_degamma = create_blob(display->drm_fd, (uint64_t *)(degamma_data), blob_length_degamma); + if (blob_id_degamma < 0) + free(degamma_data); + igt_fail_on_f (blob_id_degamma < 0, "DeGAMMA:BLOB IOCTL Fail\n"); + + } + + if (num_samples == 0) + blob_length_gamma = 1; + else + blob_length_gamma = (sizeof(struct drm_palette) + (num_samples_gamma * sizeof(struct drm_r32g32b32))); + + gamma_data = malloc(blob_length_gamma); + if (num_samples == 0) + write_gamma_lut(0, gamma_data->lut, unit_gamma); + else + write_gamma_lut(num_samples_gamma, gamma_data->lut, unit_gamma); + + blob_id_gamma = create_blob(display->drm_fd, (uint64_t *)(gamma_data), blob_length_gamma); + if (blob_id_gamma < 0) + free(gamma_data); + igt_fail_on_f (blob_id_gamma < 0, "GAMMA:BLOB IOCTL Fail\n"); + + /*Disabling degamma*/ + if (unit_gamma == 2) { + blob_length_degamma = 1; + degamma_data = malloc(blob_length_degamma); + write_gamma_lut(0, degamma_data->lut, unit_gamma); + blob_id_degamma = create_blob(display->drm_fd, (uint64_t *)(degamma_data), blob_length_degamma); + if (blob_id_degamma < 0) + free(degamma_data); + igt_fail_on_f (blob_id_degamma < 0, "DeGAMMA:BLOB IOCTL Fail\n"); + + res = set_color_property(display->drm_fd, output->config.crtc->crtc_id, + DRM_MODE_OBJECT_CRTC, "PALETTE_BEFORE_CTM", blob_id_degamma); + ret = get_color_property(display->drm_fd, output->config.crtc->crtc_id, + DRM_MODE_OBJECT_CRTC, "PALETTE_BEFORE_CTM"); + if (res < 0) + free(degamma_data); + igt_fail_on_f (res < 0, "PALETTE_BEFORE_CTM:Set Property Failed\n"); + igt_fail_on_f (ret < 0, "PALETTE_BEFORE_CTM:Set Property Failed\n"); + + } + + if (num_samples == BDW_SPLITGAMMA_MAX_VALS) { + + res = set_color_property(display->drm_fd, output->config.crtc->crtc_id, + DRM_MODE_OBJECT_CRTC, "PALETTE_BEFORE_CTM", blob_id_degamma); + ret = get_color_property(display->drm_fd, output->config.crtc->crtc_id, + DRM_MODE_OBJECT_CRTC, "PALETTE_BEFORE_CTM"); + if (res < 0) + free(degamma_data); + igt_fail_on_f (res < 0, "PALETTE_BEFORE_CTM:Set Property Failed\n"); + igt_fail_on_f (ret < 0, "PALETTE_BEFORE_CTM:Set Property Failed\n"); + free(degamma_data); + } + res = set_color_property(display->drm_fd, output->config.crtc->crtc_id, + DRM_MODE_OBJECT_CRTC, "PALETTE_AFTER_CTM", blob_id_gamma); + + if (res < 0) + free(gamma_data); + igt_fail_on_f (res < 0, "PALETTE_AFTER_CTM:Set Property Failed\n"); + + ret = get_color_property(display->drm_fd, output->config.crtc->crtc_id, + DRM_MODE_OBJECT_CRTC, "PALETTE_AFTER_CTM"); + + free(gamma_data); + igt_fail_on_f (ret < 0, "PALETTE_BEFORE_CTM:Set Property Failed\n"); +} + +static void test_pipe_gamma_invalid_tests(struct data_t *data, uint32_t num_samples, enum blob op) +{ + int res, blob_length; + struct drm_palette *gamma_data = NULL; + struct drm_mode_create_blob blob; + struct drm_mode_create_blob empty_blob; + enum pipe pipe1; + int ret = -1; + + igt_display_t *display = &data->display; + igt_output_t *output; + if (num_samples == 0) + blob_length = 1; + else + blob_length = (sizeof(struct drm_palette) + (num_samples * sizeof(struct drm_r32g32b32))); + + gamma_data = malloc(blob_length); + if (op == INVALID_BLOB_DATA) + write_gamma_lut(0, gamma_data->lut, 1); + else + write_gamma_lut(num_samples, gamma_data->lut, 1); + blob.data = (uint64_t)gamma_data; + blob.length = blob_length; + blob.blob_id = -1; + + if (op == INVALID_BLOB_LENGTH) + blob.length = 10; + + ret = ioctl(display->drm_fd, DRM_IOCTL_MODE_CREATEPROPBLOB, &blob); + igt_fail_on_f (ret < 0, "GAMMA:BLOB IOCTL Fail\n"); + + if (op == INVALID_BLOB_ID) + blob.blob_id = 4096*4096; + if (op == INVALID_BLOB_NULL) + blob = empty_blob; + for_each_connected_output(display, output) { + pipe1 = output->config.pipe; + igt_output_set_pipe(output, pipe1); + + res = set_color_property(display->drm_fd, output->config.crtc->crtc_id, + DRM_MODE_OBJECT_CRTC, "PALETTE_AFTER_CTM", blob.blob_id); + free(gamma_data); + if (op == INVALID_BLOB_DATA) + igt_fail_on_f (res < 0, "GAMMA:Invalid Data Tests Failed %d\n", res); + else + igt_fail_on_f (res >= 0, "GAMMA:Invalid Tests Failed %d\n", res); + apply_gamma(data, display, output, 0, 1); + } +} + +static void test_pipe_degamma_invalid_tests(struct data_t *data, uint32_t num_samples, enum blob op) +{ + + int res, blob_length; + struct drm_palette *degamma_data = NULL; + struct drm_mode_create_blob blob; + struct drm_mode_create_blob empty_blob; + enum pipe pipe1; + int ret = -1; + + igt_display_t *display = &data->display; + igt_output_t *output; + + if (num_samples == 0) + blob_length = 1; + else + blob_length = (sizeof(struct drm_palette) + (num_samples * sizeof(struct drm_r32g32b32))); + degamma_data = malloc(blob_length); + if (op == INVALID_BLOB_DATA) + write_gamma_lut(0, degamma_data->lut, 1); + else + write_gamma_lut(num_samples, degamma_data->lut, 1); + + blob.data = (uint64_t)degamma_data; + blob.length = blob_length; + blob.blob_id = -1; + + if (op == INVALID_BLOB_LENGTH) + blob.length = 10; + + ret = ioctl(display->drm_fd, DRM_IOCTL_MODE_CREATEPROPBLOB, &blob); + igt_fail_on_f (ret < 0, "GAMMA:BLOB IOCTL Fail\n"); + + if (op == INVALID_BLOB_ID) + blob.blob_id = 4096*4096; + if (op == INVALID_BLOB_NULL) + blob = empty_blob; + for_each_connected_output(display, output) { + pipe1 = output->config.pipe; + igt_output_set_pipe(output, pipe1); + + res = set_color_property(display->drm_fd, output->config.crtc->crtc_id, + DRM_MODE_OBJECT_CRTC, "PALETTE_BEFORE_CTM", blob.blob_id); + free(degamma_data); + if (op == INVALID_BLOB_DATA) + igt_fail_on_f (res < 0, "DEGAMMA:Invalid Data Tests Failed %d\n", res); + else + igt_fail_on_f (res >= 0, "DEGAMMA:Invalid Tests Failed %d\n", res); + apply_gamma(data, display, output, 0, 1); + } + + +} +/* +This function verify ctm feature using both CRC check. +Steps followed are: + 1.Enable Black plane and capture CRC_REFERENCE_BLACK. + 2.Enable White plane and capture CRS_REFERENCE_WHITE + 3.Enable Red plane. + 4.Apply LOW Gamma. + 5.Capture CRC_Black. + 6.Apply High Gamma and capture CRC_White. + 7.CRC_Black should be equivalent to CRC_REFERENCE_BLACK + 8.CRC_White should be equivalent to CRC_REFERENCE_WHite. + + +*/ +static void test_pipe_gamma(struct data_t *data, igt_display_t *display, igt_output_t *output, + uint32_t num_samples, int values, int pipe1) +{ + int unit_gamma, disable_gamma; + igt_crc_t crc_black, crc_white, crc_reference_white, crc_reference_black; + + + /*Enable black planes and capture reference crc*/ + + fb_color.red = 0; + fb_color.green = 0; + fb_color.blue = 0; + enable_plane(data, display, output, pipe1); + igt_pipe_crc_collect_crc(data->pipe_crc, &crc_reference_black); + /*Enable white plane and capture refernce crc*/ + fb_color.red = 1; + fb_color.green = 1; + fb_color.blue = 1; + enable_plane(data, display, output, pipe1); + igt_pipe_crc_collect_crc(data->pipe_crc, &crc_reference_white); + + /*Enable red planes and apply unit gamma*/ + fb_color.red = 1; + fb_color.green = 0; + fb_color.blue = 0; + unit_gamma = 0; /*0 -> white 1->black*/ + apply_gamma(data, display, output, num_samples, unit_gamma); + enable_plane(data, display, output, pipe1); + igt_pipe_crc_collect_crc(data->pipe_crc, &crc_white); + + /* Apply 0x0 gamma */ + unit_gamma = 1; + + apply_gamma(data, display, output, num_samples, unit_gamma); + enable_plane(data, display, output, pipe1); + igt_pipe_crc_collect_crc(data->pipe_crc, &crc_black); + igt_assert_crc_equal(&crc_reference_black, &crc_black); + igt_assert_crc_equal(&crc_reference_white, &crc_white); + + /*Disabling gamma*/ + if (num_samples == BDW_SPLITGAMMA_MAX_VALS) { + disable_gamma = 2; + apply_gamma(data, display, output, 0, disable_gamma); + } else { + apply_gamma(data, display, output, 0, unit_gamma); + } + +} + +static void test_legacy_gamma (struct data_t *data, igt_display_t *display, igt_output_t *output, int pipe1) +{ + int ret, i; + uint16_t *val = malloc(sizeof(uint16_t) * 256); + float gamma1 = 1.0; + fb_color.red = 1; + fb_color.green = 1; + fb_color.blue = 1; + enable_plane(data, display, output, pipe1); + for (i = 0; i < 256 ; i++) { + val[i] = 0xffff * pow((i/255), gamma1); + + } + for_each_connected_output (display, output) { + ret = drmModeCrtcSetGamma (display->drm_fd, output->config.crtc->crtc_id, 256, val, val, val); + igt_assert_lte(0, ret); + + } +} + +static void test_pipe_color(struct data_t *data, enum color_property prop_name, int value) +{ + igt_display_t *display = &data->display; + igt_output_t *output; + igt_plane_t *plane; + enum pipe pipe1; + int res; + + + for_each_connected_output(display, output) { + pipe1 = output->config.pipe; + igt_output_set_pipe(output, pipe1); + res = get_color_property(display->drm_fd, output->config.crtc->crtc_id, DRM_MODE_OBJECT_CRTC, "CTM"); + igt_require (res >= 0); + res = get_color_property(display->drm_fd, output->config.crtc->crtc_id, DRM_MODE_OBJECT_CRTC, "PALETTE_BEFORE_CTM"); + igt_require (res >= 0); + res = get_color_property(display->drm_fd, output->config.crtc->crtc_id, DRM_MODE_OBJECT_CRTC, "PALETTE_AFTER_CTM"); + igt_require (res >= 0); + + switch (prop_name) { + case gamma_property_8bit: + test_pipe_gamma(data, display, output, + BDW_8BIT_GAMMA_MAX_VALS, value, pipe1); + break; + case legacy_gamma: + test_legacy_gamma(data, display, output, pipe1); + break; + case gamma_property_10bit: + test_pipe_gamma(data, display, output, BDW_10BIT_GAMMA_MAX_VALS, value, pipe1); + break; + case ctm_property: + switch (value) { + case REVERSE: + test_pipe_ctm_reverse(data, display, output, value, pipe1); + break; + case NEGATIVE: + test_pipe_ctm_negative(data, display, output, value, pipe1); + break; + case FRACTION: + test_pipe_ctm_fraction(data, display, output, value, pipe1); + break; + default: + test_pipe_ctm(data, display, output, value, pipe1); + break; + } + break; + case gamma_property_split: + test_pipe_gamma(data, display, output, + BDW_SPLITGAMMA_MAX_VALS, value, pipe1); + break; + case gamma_property_12bit: + test_pipe_gamma(data, display, output, + BDW_12BIT_GAMMA_MAX_VALS, value, pipe1); + break; + default: + igt_info("Invalid Test\n"); + break; + } + + plane = igt_output_get_plane(output, IGT_PLANE_2); + cleanup_crtc(data, output, plane); + } +} + + +igt_main +{ + struct data_t data = {}; + int values = 1; + igt_skip_on_simulation(); + igt_fixture{ + data.drm_fd = drm_open_driver_master(DRIVER_INTEL); + kmstest_set_vt_graphics_mode(); + igt_display_init(&data.display, data.drm_fd); + igt_require_pipe_crc(); + } + + igt_subtest("ctm-red") + test_pipe_color(&data, ctm_property, RED); + igt_subtest("ctm-green") + test_pipe_color(&data, ctm_property, GREEN); + igt_subtest("ctm-blue") + test_pipe_color(&data, ctm_property, BLUE); + igt_subtest("ctm-reverse") + test_pipe_color(&data, ctm_property, REVERSE); + igt_subtest("ctm-negative") + test_pipe_color(&data, ctm_property, NEGATIVE); + igt_subtest("ctm-fraction") + test_pipe_color(&data, ctm_property, FRACTION); + igt_subtest("ctm-invalid-blob-id") + test_pipe_ctm_invalid_tests(&data, INVALID_BLOB_ID); + igt_subtest("ctm-invalid-blob-null") + test_pipe_ctm_invalid_tests(&data, INVALID_BLOB_NULL); + igt_subtest("ctm-invalid-blob-length") + test_pipe_ctm_invalid_tests(&data, INVALID_BLOB_LENGTH); + igt_subtest("gamma-legacy") + test_pipe_color(&data, legacy_gamma, values); + igt_subtest("gamma-8bit") + test_pipe_color(&data, gamma_property_8bit, values); + igt_subtest("gamma-10bit") + test_pipe_color(&data, gamma_property_10bit, values); + igt_subtest("gamma-12bit") + test_pipe_color(&data, gamma_property_12bit, values); + igt_subtest("gamma-split") + test_pipe_color(&data, gamma_property_split, values); + igt_subtest("gamma-invalid-blob-id") + test_pipe_gamma_invalid_tests(&data, BDW_12BIT_GAMMA_MAX_VALS, INVALID_BLOB_ID); + igt_subtest("gamma-invalid-blob-null") + test_pipe_gamma_invalid_tests(&data, BDW_12BIT_GAMMA_MAX_VALS, INVALID_BLOB_NULL); + igt_subtest("gamma-invalid-blob-length") + test_pipe_gamma_invalid_tests(&data, BDW_12BIT_GAMMA_MAX_VALS, INVALID_BLOB_LENGTH); + igt_subtest("gamma-8bit-invalid-blob-data") + test_pipe_gamma_invalid_tests(&data, BDW_8BIT_GAMMA_MAX_VALS, INVALID_BLOB_DATA); + igt_subtest("gamma-10bit-invalid-blob-data") + test_pipe_gamma_invalid_tests(&data, BDW_10BIT_GAMMA_MAX_VALS, INVALID_BLOB_DATA); + igt_subtest("gamma-12bit-invalid-blob-data") + test_pipe_gamma_invalid_tests(&data, BDW_12BIT_GAMMA_MAX_VALS, INVALID_BLOB_DATA); + igt_subtest("degamma-invalid-blob-id") + test_pipe_degamma_invalid_tests(&data, BDW_12BIT_GAMMA_MAX_VALS, INVALID_BLOB_ID); + igt_subtest("degamma-invalid-blob-null") + test_pipe_degamma_invalid_tests(&data, BDW_12BIT_GAMMA_MAX_VALS, INVALID_BLOB_NULL); + igt_subtest("degamma-invalid-blob-length") + test_pipe_degamma_invalid_tests(&data, BDW_12BIT_GAMMA_MAX_VALS, INVALID_BLOB_LENGTH); + igt_subtest("degamma-8bit-invalid-blob-data") + test_pipe_degamma_invalid_tests(&data, BDW_8BIT_GAMMA_MAX_VALS, INVALID_BLOB_DATA); + igt_subtest("degamma-10bit-invalid-blob-data") + test_pipe_degamma_invalid_tests(&data, BDW_10BIT_GAMMA_MAX_VALS, INVALID_BLOB_DATA); + igt_subtest("degamma-12bit-invalid-blob-data") + test_pipe_degamma_invalid_tests(&data, BDW_12BIT_GAMMA_MAX_VALS, INVALID_BLOB_DATA); + + igt_fixture{ + igt_display_fini(&data.display); + } +} +