From patchwork Fri Jul 14 15:18:50 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Liviu Dudau X-Patchwork-Id: 107811 Delivered-To: patch@linaro.org Received: by 10.140.101.44 with SMTP id t41csp1035284qge; Fri, 14 Jul 2017 08:20:08 -0700 (PDT) X-Received: by 10.99.44.81 with SMTP id s78mr15531548pgs.146.1500045608011; Fri, 14 Jul 2017 08:20:08 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1500045608; cv=none; d=google.com; s=arc-20160816; b=XaM4TzHdvNKfN8ggIG/LuFjL7s6xop5TpBq3bQkQWVzvZqOSiRNlMQF5O0Hf0KphP7 Hbw0dzD3ZHSTGhXtXsROq0athQy7cpuORZOFronttoRyGh79xYuFSLtmLeVSNbPqFwkk QIuJI96HUTGPab3Xv6oPZjaBz1ci1/Zi90ODd4rP3/dfllaEsZMW9k16FV1qOrV8pDlP qqTx3nNui7fKRTzY8OlrxwdcF0A7bW/r9d39wOplJuAsXmuXuA7IcL27UHRD7ks43U7h O8v4iIu9NJxaUrkFZqTuEAiLJUKVND6AuKLhkW5hmHja2RPaQ5UToNhBMMyKj7ShDqj/ kO+g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:list-subscribe:list-help :list-post:list-archive:list-unsubscribe:list-id:precedence:cc :mime-version:references:in-reply-to:message-id:date:subject:to:from :delivered-to:arc-authentication-results; bh=slLBYkER0YZgn1SuQNGu1E/l30IOXV6KZo6i7K6x+sw=; b=sVL286mYpP8NaIq1mus/qKfyNfnv95kWhJCrdnqoDItkB9C5UpcNFsJo35G2MIZvRu MaGPtyncvTWXvXmGYX8bWge0ui0oSmHryUlU6kxIVj4NR1L9pzmAx4lbh6ghxITryebG FCeYkxCSdQuz6rjQBl5dF7XFY0TlXYiebEvs43ujHDJcVLhRWXLrp/fxtC+YchPWpPVf hmpUP4GlwOTWgCUs5FZYQLS7tYxwdXpY1nkT5ay3fo9oDfJnkc07FoJSKt/hMJ61WweK tsTiXwWJsriOfyiDuUkqNUtHbuX1e/0YMZSwI/KV8YXHBY/LEV+p7IocHl+MoMegXiSI 0rsQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of dri-devel-bounces@lists.freedesktop.org designates 131.252.210.177 as permitted sender) smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Return-Path: Received: from gabe.freedesktop.org (gabe.freedesktop.org. [131.252.210.177]) by mx.google.com with ESMTPS id t67si6770964pgt.339.2017.07.14.08.20.07 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 14 Jul 2017 08:20:07 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of dri-devel-bounces@lists.freedesktop.org designates 131.252.210.177 as permitted sender) client-ip=131.252.210.177; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of dri-devel-bounces@lists.freedesktop.org designates 131.252.210.177 as permitted sender) smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 18FBB6E87F; Fri, 14 Jul 2017 15:19:08 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from cam-smtp0.cambridge.arm.com (fw-tnat.cambridge.arm.com [217.140.96.140]) by gabe.freedesktop.org (Postfix) with ESMTPS id A2F426E869; Fri, 14 Jul 2017 15:19:01 +0000 (UTC) Received: from e110455-lin.cambridge.arm.com (e110455-lin.cambridge.arm.com [10.2.131.9]) by cam-smtp0.cambridge.arm.com (8.13.8/8.13.8) with ESMTP id v6EFIuFK000867; Fri, 14 Jul 2017 16:18:56 +0100 From: Liviu Dudau To: Intel GFX discussion Subject: [PATCH i-g-t v2 1/7] igt: lib/igt_crc: Split out CRC functionality Date: Fri, 14 Jul 2017 16:18:50 +0100 Message-Id: <20170714151856.32041-2-liviu.dudau@arm.com> X-Mailer: git-send-email 2.13.2 In-Reply-To: <20170714151856.32041-1-liviu.dudau@arm.com> References: <20170714151856.32041-1-liviu.dudau@arm.com> MIME-Version: 1.0 Cc: Boris Brezillon , DRI devel X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" From: Brian Starkey Separate out the CRC code for better compartmentalisation. Should ease the addition of more/different CRC sources in the future. Signed-off-by: Brian Starkey Acked-by: Daniel Vetter --- lib/Makefile.sources | 2 + lib/igt_chamelium.h | 1 + lib/igt_crc.c | 563 ++++++++++++++++++++++++++++++++++++++ lib/igt_crc.h | 125 +++++++++ lib/igt_debugfs.c | 547 ------------------------------------ lib/igt_debugfs.h | 81 ------ tests/chamelium.c | 1 + tests/kms_atomic_transition.c | 1 + tests/kms_ccs.c | 1 + tests/kms_chv_cursor_fail.c | 1 + tests/kms_crtc_background_color.c | 1 + tests/kms_cursor_crc.c | 1 + tests/kms_cursor_legacy.c | 1 + tests/kms_draw_crc.c | 1 + tests/kms_fbc_crc.c | 1 + tests/kms_flip_tiling.c | 1 + tests/kms_frontbuffer_tracking.c | 1 + tests/kms_mmap_write_crc.c | 1 + tests/kms_mmio_vs_cs_flip.c | 1 + tests/kms_pipe_color.c | 1 + tests/kms_pipe_crc_basic.c | 1 + tests/kms_plane.c | 1 + tests/kms_plane_lowres.c | 1 + tests/kms_plane_multiple.c | 1 + tests/kms_plane_scaling.c | 1 + tests/kms_pwrite_crc.c | 1 + tests/kms_rotation_crc.c | 1 + tests/kms_universal_plane.c | 1 + tools/intel_display_crc.c | 1 + 29 files changed, 714 insertions(+), 628 deletions(-) create mode 100644 lib/igt_crc.c create mode 100644 lib/igt_crc.h diff --git a/lib/Makefile.sources b/lib/Makefile.sources index 53fdb54c..cfba15c9 100644 --- a/lib/Makefile.sources +++ b/lib/Makefile.sources @@ -11,6 +11,8 @@ lib_source_list = \ igt_debugfs.h \ igt_aux.c \ igt_aux.h \ + igt_crc.c \ + igt_crc.h \ igt_edid_template.h \ igt_gt.c \ igt_gt.h \ diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h index 81322ad2..ea5abc2e 100644 --- a/lib/igt_chamelium.h +++ b/lib/igt_chamelium.h @@ -31,6 +31,7 @@ #endif #include "igt.h" +#include "igt_crc.h" #include struct chamelium; diff --git a/lib/igt_crc.c b/lib/igt_crc.c new file mode 100644 index 00000000..91a0b5a8 --- /dev/null +++ b/lib/igt_crc.c @@ -0,0 +1,563 @@ +/* + * Copyright © 2013 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. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "igt_aux.h" +#include "igt_crc.h" +#include "igt_core.h" +#include "igt_debugfs.h" +#include "igt_kms.h" + +/** + * igt_assert_crc_equal: + * @a: first pipe CRC value + * @b: second pipe CRC value + * + * Compares two CRC values and fails the testcase if they don't match with + * igt_fail(). Note that due to CRC collisions CRC based testcase can only + * assert that CRCs match, never that they are different. Otherwise there might + * be random testcase failures when different screen contents end up with the + * same CRC by chance. + */ +void igt_assert_crc_equal(const igt_crc_t *a, const igt_crc_t *b) +{ + int i; + + for (i = 0; i < a->n_words; i++) + igt_assert_eq_u32(a->crc[i], b->crc[i]); +} + +/** + * igt_crc_to_string: + * @crc: pipe CRC value to print + * + * This formats @crc into a string buffer which is owned by igt_crc_to_string(). + * The next call will override the buffer again, which makes this multithreading + * unsafe. + * + * This should only ever be used for diagnostic debug output. + */ +char *igt_crc_to_string(igt_crc_t *crc) +{ + int i; + char buf[128] = { 0 }; + + for (i = 0; i < crc->n_words; i++) + sprintf(buf + strlen(buf), "%08x ", crc->crc[i]); + + return strdup(buf); +} + +#define MAX_CRC_ENTRIES 10 +#define MAX_LINE_LEN (10 + 11 * MAX_CRC_ENTRIES + 1) + +/* (6 fields, 8 chars each, space separated (5) + '\n') */ +#define LEGACY_LINE_LEN (6 * 8 + 5 + 1) + +struct _igt_pipe_crc { + int fd; + int dir; + int ctl_fd; + int crc_fd; + int flags; + bool is_legacy; + + enum pipe pipe; + enum intel_pipe_crc_source source; +}; + +static const char *pipe_crc_sources[] = { + "none", + "plane1", + "plane2", + "pf", + "pipe", + "TV", + "DP-B", + "DP-C", + "DP-D", + "auto" +}; + +static const char *pipe_crc_source_name(enum intel_pipe_crc_source source) +{ + return pipe_crc_sources[source]; +} + +static bool igt_pipe_crc_do_start(igt_pipe_crc_t *pipe_crc) +{ + char buf[64]; + + /* Stop first just to make sure we don't have lingering state left. */ + igt_pipe_crc_stop(pipe_crc); + + if (pipe_crc->is_legacy) + sprintf(buf, "pipe %s %s", kmstest_pipe_name(pipe_crc->pipe), + pipe_crc_source_name(pipe_crc->source)); + else + sprintf(buf, "%s", pipe_crc_source_name(pipe_crc->source)); + + igt_assert_eq(write(pipe_crc->ctl_fd, buf, strlen(buf)), strlen(buf)); + + if (!pipe_crc->is_legacy) { + int err; + + sprintf(buf, "crtc-%d/crc/data", pipe_crc->pipe); + err = 0; + + pipe_crc->crc_fd = openat(pipe_crc->dir, buf, pipe_crc->flags); + if (pipe_crc->crc_fd < 0) + err = -errno; + + if (err == -EINVAL) + return false; + + igt_assert_eq(err, 0); + } + + errno = 0; + return true; +} + +static void igt_pipe_crc_pipe_off(int fd, enum pipe pipe) +{ + char buf[32]; + + sprintf(buf, "pipe %s none", kmstest_pipe_name(pipe)); + igt_assert_eq(write(fd, buf, strlen(buf)), strlen(buf)); +} + +static void igt_pipe_crc_reset(int drm_fd) +{ + struct dirent *dirent; + const char *cmd = "none"; + bool done = false; + DIR *dir; + int fdir; + int fd; + + fdir = igt_debugfs_dir(drm_fd); + if (fdir < 0) + return; + + dir = fdopendir(fdir); + if (!dir) { + close(fdir); + return; + } + + while ((dirent = readdir(dir))) { + char buf[128]; + + if (strcmp(dirent->d_name, "crtc-") != 0) + continue; + + sprintf(buf, "%s/crc/control", dirent->d_name); + fd = openat(fdir, buf, O_WRONLY); + if (fd < 0) + continue; + + igt_assert_eq(write(fd, cmd, strlen(cmd)), strlen(cmd)); + close(fd); + + done = true; + } + closedir(dir); + + if (!done) { + fd = openat(fdir, "i915_display_crtc_ctl", O_WRONLY); + if (fd != -1) { + igt_pipe_crc_pipe_off(fd, PIPE_A); + igt_pipe_crc_pipe_off(fd, PIPE_B); + igt_pipe_crc_pipe_off(fd, PIPE_C); + + close(fd); + } + } + + close(fdir); +} + +static void pipe_crc_exit_handler(int sig) +{ + struct dirent *dirent; + char buf[128]; + DIR *dir; + int fd; + + dir = opendir("/dev/dri"); + if (!dir) + return; + + /* + * Try to reset CRC capture for all DRM devices, this is only needed + * for the legacy CRC ABI and can be completely removed once the + * legacy codepaths are removed. + */ + while ((dirent = readdir(dir))) { + if (strncmp(dirent->d_name, "card", 4) != 0) + continue; + + sprintf(buf, "/dev/dri/%s", dirent->d_name); + fd = open(buf, O_WRONLY); + + igt_pipe_crc_reset(fd); + + close(fd); + } + closedir(dir); +} + +/** + * igt_require_pipe_crc: + * + * Convenience helper to check whether pipe CRC capturing is supported by the + * kernel. Uses igt_skip to automatically skip the test/subtest if this isn't + * the case. + */ +void igt_require_pipe_crc(int fd) +{ + const char *cmd = "pipe A none"; + int ctl, written; + + ctl = igt_debugfs_open(fd, "crtc-0/crc/control", O_RDONLY); + if (ctl < 0) { + ctl = igt_debugfs_open(fd, "i915_display_crc_ctl", O_WRONLY); + igt_require_f(ctl, + "No display_crc_ctl found, kernel too old\n"); + + written = write(ctl, cmd, strlen(cmd)); + igt_require_f(written < 0, + "CRCs not supported on this platform\n"); + } + close(ctl); +} + +static igt_pipe_crc_t * +pipe_crc_new(int fd, enum pipe pipe, enum intel_pipe_crc_source source, int flags) +{ + igt_pipe_crc_t *pipe_crc; + char buf[128]; + int debugfs; + + debugfs = igt_debugfs_dir(fd); + igt_assert(debugfs != -1); + + igt_install_exit_handler(pipe_crc_exit_handler); + + pipe_crc = calloc(1, sizeof(struct _igt_pipe_crc)); + + sprintf(buf, "crtc-%d/crc/control", pipe); + pipe_crc->ctl_fd = openat(debugfs, buf, O_WRONLY); + if (pipe_crc->ctl_fd == -1) { + pipe_crc->ctl_fd = openat(debugfs, + "i915_display_crc_ctl", O_WRONLY); + igt_assert(pipe_crc->ctl_fd != -1); + pipe_crc->is_legacy = true; + } + + if (pipe_crc->is_legacy) { + sprintf(buf, "i915_pipe_%s_crc", kmstest_pipe_name(pipe)); + pipe_crc->crc_fd = openat(debugfs, buf, flags); + igt_assert(pipe_crc->crc_fd != -1); + igt_debug("Using legacy frame CRC ABI\n"); + } else { + pipe_crc->crc_fd = -1; + igt_debug("Using generic frame CRC ABI\n"); + } + + pipe_crc->fd = fd; + pipe_crc->dir = debugfs; + pipe_crc->pipe = pipe; + pipe_crc->source = source; + pipe_crc->flags = flags; + + return pipe_crc; +} + +/** + * igt_pipe_crc_new: + * @pipe: display pipe to use as source + * @source: CRC tap point to use as source + * + * This sets up a new pipe CRC capture object for the given @pipe and @source + * in blocking mode. + * + * Returns: A pipe CRC object for the given @pipe and @source. The library + * assumes that the source is always available since recent kernels support at + * least INTEL_PIPE_CRC_SOURCE_AUTO everywhere. + */ +igt_pipe_crc_t * +igt_pipe_crc_new(int fd, enum pipe pipe, enum intel_pipe_crc_source source) +{ + return pipe_crc_new(fd, pipe, source, O_RDONLY); +} + +/** + * igt_pipe_crc_new_nonblock: + * @pipe: display pipe to use as source + * @source: CRC tap point to use as source + * + * This sets up a new pipe CRC capture object for the given @pipe and @source + * in nonblocking mode. + * + * Returns: A pipe CRC object for the given @pipe and @source. The library + * assumes that the source is always available since recent kernels support at + * least INTEL_PIPE_CRC_SOURCE_AUTO everywhere. + */ +igt_pipe_crc_t * +igt_pipe_crc_new_nonblock(int fd, enum pipe pipe, enum intel_pipe_crc_source source) +{ + return pipe_crc_new(fd, pipe, source, O_RDONLY | O_NONBLOCK); +} + +/** + * igt_pipe_crc_free: + * @pipe_crc: pipe CRC object + * + * Frees all resources associated with @pipe_crc. + */ +void igt_pipe_crc_free(igt_pipe_crc_t *pipe_crc) +{ + if (!pipe_crc) + return; + + close(pipe_crc->ctl_fd); + close(pipe_crc->crc_fd); + close(pipe_crc->dir); + free(pipe_crc); +} + +static bool pipe_crc_init_from_string(igt_pipe_crc_t *pipe_crc, igt_crc_t *crc, + const char *line) +{ + int n, i; + const char *buf; + + if (pipe_crc->is_legacy) { + crc->has_valid_frame = true; + crc->n_words = 5; + n = sscanf(line, "%8u %8x %8x %8x %8x %8x", &crc->frame, + &crc->crc[0], &crc->crc[1], &crc->crc[2], + &crc->crc[3], &crc->crc[4]); + return n == 6; + } + + if (strncmp(line, "XXXXXXXXXX", 10) == 0) + crc->has_valid_frame = false; + else { + crc->has_valid_frame = true; + crc->frame = strtoul(line, NULL, 16); + } + + buf = line + 10; + for (i = 0; *buf != '\n'; i++, buf += 11) + crc->crc[i] = strtoul(buf, NULL, 16); + + crc->n_words = i; + + return true; +} + +static int read_crc(igt_pipe_crc_t *pipe_crc, igt_crc_t *out) +{ + ssize_t bytes_read; + char buf[MAX_LINE_LEN + 1]; + size_t read_len; + + if (pipe_crc->is_legacy) + read_len = LEGACY_LINE_LEN; + else + read_len = MAX_LINE_LEN; + + igt_set_timeout(5, "CRC reading"); + bytes_read = read(pipe_crc->crc_fd, &buf, read_len); + igt_reset_timeout(); + + if (bytes_read < 0 && errno == EAGAIN) + igt_assert(pipe_crc->flags & O_NONBLOCK); + + if (bytes_read < 0) + bytes_read = 0; + + buf[bytes_read] = '\0'; + + if (bytes_read && !pipe_crc_init_from_string(pipe_crc, out, buf)) + return -EINVAL; + + return bytes_read; +} + +static void read_one_crc(igt_pipe_crc_t *pipe_crc, igt_crc_t *out) +{ + while (read_crc(pipe_crc, out) == 0) + usleep(1000); +} + +/** + * igt_pipe_crc_start: + * @pipe_crc: pipe CRC object + * + * Starts the CRC capture process on @pipe_crc. + */ +void igt_pipe_crc_start(igt_pipe_crc_t *pipe_crc) +{ + igt_crc_t crc; + + igt_assert(igt_pipe_crc_do_start(pipe_crc)); + + if (pipe_crc->is_legacy) { + /* + * For some no yet identified reason, the first CRC is + * bonkers. So let's just wait for the next vblank and read + * out the buggy result. + * + * On CHV sometimes the second CRC is bonkers as well, so + * don't trust that one either. + */ + read_one_crc(pipe_crc, &crc); + read_one_crc(pipe_crc, &crc); + } +} + +/** + * igt_pipe_crc_stop: + * @pipe_crc: pipe CRC object + * + * Stops the CRC capture process on @pipe_crc. + */ +void igt_pipe_crc_stop(igt_pipe_crc_t *pipe_crc) +{ + char buf[32]; + + if (pipe_crc->is_legacy) { + sprintf(buf, "pipe %s none", kmstest_pipe_name(pipe_crc->pipe)); + igt_assert_eq(write(pipe_crc->ctl_fd, buf, strlen(buf)), + strlen(buf)); + } else { + close(pipe_crc->crc_fd); + pipe_crc->crc_fd = -1; + } +} + +/** + * igt_pipe_crc_get_crcs: + * @pipe_crc: pipe CRC object + * @n_crcs: number of CRCs to capture + * @out_crcs: buffer pointer for the captured CRC values + * + * Read up to @n_crcs from @pipe_crc. This function does not block, and will + * return early if not enough CRCs can be captured, if @pipe_crc has been + * opened using igt_pipe_crc_new_nonblock(). It will block until @n_crcs are + * retrieved if @pipe_crc has been opened using igt_pipe_crc_new(). @out_crcs is + * alloced by this function and must be released with free() by the caller. + * + * Callers must start and stop the capturing themselves by calling + * igt_pipe_crc_start() and igt_pipe_crc_stop(). For one-shot CRC collecting + * look at igt_pipe_crc_collect_crc(). + * + * Returns: + * The number of CRCs captured. Should be equal to @n_crcs in blocking mode, but + * can be less (even zero) in non-blocking mode. + */ +int +igt_pipe_crc_get_crcs(igt_pipe_crc_t *pipe_crc, int n_crcs, + igt_crc_t **out_crcs) +{ + igt_crc_t *crcs; + int n = 0; + + crcs = calloc(n_crcs, sizeof(igt_crc_t)); + + do { + igt_crc_t *crc = &crcs[n]; + int ret; + + ret = read_crc(pipe_crc, crc); + if (ret < 0) + continue; + if (ret == 0) + break; + + n++; + } while (n < n_crcs); + + *out_crcs = crcs; + return n; +} + +static void crc_sanity_checks(igt_crc_t *crc) +{ + int i; + bool all_zero = true; + + for (i = 0; i < crc->n_words; i++) { + igt_warn_on_f(crc->crc[i] == 0xffffffff, + "Suspicious CRC: it looks like the CRC " + "read back was from a register in a powered " + "down well\n"); + if (crc->crc[i]) + all_zero = false; + } + + igt_warn_on_f(all_zero, "Suspicious CRC: All values are 0.\n"); +} + +/** + * igt_pipe_crc_collect_crc: + * @pipe_crc: pipe CRC object + * @out_crc: buffer for the captured CRC values + * + * Read a single CRC from @pipe_crc. This function blocks until the CRC is + * retrieved, irrespective of whether @pipe_crc has been opened with + * igt_pipe_crc_new() or igt_pipe_crc_new_nonblock(). @out_crc must be + * allocated by the caller. + * + * This function takes care of the pipe_crc book-keeping, it will start/stop + * the collection of the CRC. + * + * This function also calls the interactive debug with the "crc" domain, so you + * can make use of this feature to actually see the screen that is being CRC'd. + * + * For continuous CRC collection look at igt_pipe_crc_start(), + * igt_pipe_crc_get_crcs() and igt_pipe_crc_stop(). + */ +void igt_pipe_crc_collect_crc(igt_pipe_crc_t *pipe_crc, igt_crc_t *out_crc) +{ + igt_debug_wait_for_keypress("crc"); + + igt_pipe_crc_start(pipe_crc); + read_one_crc(pipe_crc, out_crc); + igt_pipe_crc_stop(pipe_crc); + + crc_sanity_checks(out_crc); +} + diff --git a/lib/igt_crc.h b/lib/igt_crc.h new file mode 100644 index 00000000..b0623baf --- /dev/null +++ b/lib/igt_crc.h @@ -0,0 +1,125 @@ +/* + * Copyright © 2013 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. + * + * # Pipe CRC Support + * + * This library wraps up the kernel's support for capturing pipe CRCs into a + * neat and tidy package. For the detailed usage see all the functions which + * work on #igt_pipe_crc_t. This is supported on all platforms and outputs. + * + * Actually using pipe CRCs to write modeset tests is a bit tricky though, so + * there is no way to directly check a CRC: Both the details of the plane + * blending, color correction and other hardware and how exactly the CRC is + * computed at each tap point vary by hardware generation and are not disclosed. + * + * The only way to use #igt_crc_t CRCs therefore is to compare CRCs among each + * another either for equality or difference. Otherwise CRCs must be treated as + * completely opaque values. Note that not even CRCs from different pipes or tap + * points on the same platform can be compared. Hence only use + * igt_assert_crc_equal() to inspect CRC values captured by the same + * #igt_pipe_crc_t object. + */ + +#ifndef __IGT_CRC_H__ +#define __IGT_CRC_H__ + +#include +#include + +enum pipe; + +/** + * igt_pipe_crc_t: + * + * Pipe CRC support structure. Needs to be allocated and set up with + * igt_pipe_crc_new() for a specific pipe and pipe CRC source value. + */ +typedef struct _igt_pipe_crc igt_pipe_crc_t; + +#define DRM_MAX_CRC_NR 10 +/** + * igt_crc_t: + * @frame: frame number of the capture CRC + * @n_words: internal field, don't access + * @crc: internal field, don't access + * + * Pipe CRC value. All other members than @frame are private and should not be + * inspected by testcases. + */ +typedef struct { + uint32_t frame; + bool has_valid_frame; + int n_words; + uint32_t crc[DRM_MAX_CRC_NR]; +} igt_crc_t; + +/** + * intel_pipe_crc_source: + * @INTEL_PIPE_CRC_SOURCE_NONE: No source + * @INTEL_PIPE_CRC_SOURCE_PLANE1: Plane 1 + * @INTEL_PIPE_CRC_SOURCE_PLANE2: Plane 2 + * @INTEL_PIPE_CRC_SOURCE_PF: Panel Filter + * @INTEL_PIPE_CRC_SOURCE_PIPE: Pipe + * @INTEL_PIPE_CRC_SOURCE_TV: TV + * @INTEL_PIPE_CRC_SOURCE_DP_B: DisplayPort B + * @INTEL_PIPE_CRC_SOURCE_DP_C: DisplayPort C + * @INTEL_PIPE_CRC_SOURCE_DP_D: DisplayPort D + * @INTEL_PIPE_CRC_SOURCE_AUTO: Automatic source selection + * @INTEL_PIPE_CRC_SOURCE_MAX: Number of available sources + * + * Enumeration of all supported pipe CRC sources. Not all platforms and all + * outputs support all of them. Generic tests should just use + * INTEL_PIPE_CRC_SOURCE_AUTO. It should always map to an end-of-pipe CRC + * suitable for checking planes, cursor, color correction and any other + * output-agnostic features. + */ +enum intel_pipe_crc_source { + INTEL_PIPE_CRC_SOURCE_NONE, + INTEL_PIPE_CRC_SOURCE_PLANE1, + INTEL_PIPE_CRC_SOURCE_PLANE2, + INTEL_PIPE_CRC_SOURCE_PF, + INTEL_PIPE_CRC_SOURCE_PIPE, + INTEL_PIPE_CRC_SOURCE_TV, + INTEL_PIPE_CRC_SOURCE_DP_B, + INTEL_PIPE_CRC_SOURCE_DP_C, + INTEL_PIPE_CRC_SOURCE_DP_D, + INTEL_PIPE_CRC_SOURCE_AUTO, + INTEL_PIPE_CRC_SOURCE_MAX, +}; + +void igt_assert_crc_equal(const igt_crc_t *a, const igt_crc_t *b); +char *igt_crc_to_string(igt_crc_t *crc); + +void igt_require_pipe_crc(int fd); +igt_pipe_crc_t * +igt_pipe_crc_new(int fd, enum pipe pipe, enum intel_pipe_crc_source source); +igt_pipe_crc_t * +igt_pipe_crc_new_nonblock(int fd, enum pipe pipe, enum intel_pipe_crc_source source); +void igt_pipe_crc_free(igt_pipe_crc_t *pipe_crc); +void igt_pipe_crc_start(igt_pipe_crc_t *pipe_crc); +void igt_pipe_crc_stop(igt_pipe_crc_t *pipe_crc); +__attribute__((warn_unused_result)) +int igt_pipe_crc_get_crcs(igt_pipe_crc_t *pipe_crc, int n_crcs, + igt_crc_t **out_crcs); +void igt_pipe_crc_collect_crc(igt_pipe_crc_t *pipe_crc, igt_crc_t *out_crc); + +#endif /* __IGT_CRC_H__ */ diff --git a/lib/igt_debugfs.c b/lib/igt_debugfs.c index 80f25c61..e08b7ae8 100644 --- a/lib/igt_debugfs.c +++ b/lib/igt_debugfs.c @@ -51,24 +51,6 @@ * basic functions to access debugfs files with e.g. igt_debugfs_open() it also * provides higher-level wrappers for some debugfs features. * - * # Pipe CRC Support - * - * This library wraps up the kernel's support for capturing pipe CRCs into a - * neat and tidy package. For the detailed usage see all the functions which - * work on #igt_pipe_crc_t. This is supported on all platforms and outputs. - * - * Actually using pipe CRCs to write modeset tests is a bit tricky though, so - * there is no way to directly check a CRC: Both the details of the plane - * blending, color correction and other hardware and how exactly the CRC is - * computed at each tap point vary by hardware generation and are not disclosed. - * - * The only way to use #igt_crc_t CRCs therefore is to compare CRCs among each - * another either for equality or difference. Otherwise CRCs must be treated as - * completely opaque values. Note that not even CRCs from different pipes or tap - * points on the same platform can be compared. Hence only use - * igt_assert_crc_equal() to inspect CRC values captured by the same - * #igt_pipe_crc_t object. - * * # Other debugfs interface wrappers * * This covers the miscellaneous debugfs interface wrappers: @@ -277,235 +259,6 @@ bool igt_debugfs_search(int device, const char *filename, const char *substring) return matched; } -/* - * Pipe CRC - */ - -/** - * igt_assert_crc_equal: - * @a: first pipe CRC value - * @b: second pipe CRC value - * - * Compares two CRC values and fails the testcase if they don't match with - * igt_fail(). Note that due to CRC collisions CRC based testcase can only - * assert that CRCs match, never that they are different. Otherwise there might - * be random testcase failures when different screen contents end up with the - * same CRC by chance. - */ -void igt_assert_crc_equal(const igt_crc_t *a, const igt_crc_t *b) -{ - int i; - - for (i = 0; i < a->n_words; i++) - igt_assert_eq_u32(a->crc[i], b->crc[i]); -} - -/** - * igt_crc_to_string: - * @crc: pipe CRC value to print - * - * This formats @crc into a string buffer which is owned by igt_crc_to_string(). - * The next call will override the buffer again, which makes this multithreading - * unsafe. - * - * This should only ever be used for diagnostic debug output. - */ -char *igt_crc_to_string(igt_crc_t *crc) -{ - int i; - char buf[128] = { 0 }; - - for (i = 0; i < crc->n_words; i++) - sprintf(buf + strlen(buf), "%08x ", crc->crc[i]); - - return strdup(buf); -} - -#define MAX_CRC_ENTRIES 10 -#define MAX_LINE_LEN (10 + 11 * MAX_CRC_ENTRIES + 1) - -/* (6 fields, 8 chars each, space separated (5) + '\n') */ -#define LEGACY_LINE_LEN (6 * 8 + 5 + 1) - -struct _igt_pipe_crc { - int fd; - int dir; - int ctl_fd; - int crc_fd; - int flags; - bool is_legacy; - - enum pipe pipe; - enum intel_pipe_crc_source source; -}; - -static const char *pipe_crc_sources[] = { - "none", - "plane1", - "plane2", - "pf", - "pipe", - "TV", - "DP-B", - "DP-C", - "DP-D", - "auto" -}; - -static const char *pipe_crc_source_name(enum intel_pipe_crc_source source) -{ - return pipe_crc_sources[source]; -} - -static bool igt_pipe_crc_do_start(igt_pipe_crc_t *pipe_crc) -{ - char buf[64]; - - /* Stop first just to make sure we don't have lingering state left. */ - igt_pipe_crc_stop(pipe_crc); - - if (pipe_crc->is_legacy) - sprintf(buf, "pipe %s %s", kmstest_pipe_name(pipe_crc->pipe), - pipe_crc_source_name(pipe_crc->source)); - else - sprintf(buf, "%s", pipe_crc_source_name(pipe_crc->source)); - - igt_assert_eq(write(pipe_crc->ctl_fd, buf, strlen(buf)), strlen(buf)); - - if (!pipe_crc->is_legacy) { - int err; - - sprintf(buf, "crtc-%d/crc/data", pipe_crc->pipe); - err = 0; - - pipe_crc->crc_fd = openat(pipe_crc->dir, buf, pipe_crc->flags); - if (pipe_crc->crc_fd < 0) - err = -errno; - - if (err == -EINVAL) - return false; - - igt_assert_eq(err, 0); - } - - errno = 0; - return true; -} - -static void igt_pipe_crc_pipe_off(int fd, enum pipe pipe) -{ - char buf[32]; - - sprintf(buf, "pipe %s none", kmstest_pipe_name(pipe)); - igt_assert_eq(write(fd, buf, strlen(buf)), strlen(buf)); -} - -static void igt_pipe_crc_reset(int drm_fd) -{ - struct dirent *dirent; - const char *cmd = "none"; - bool done = false; - DIR *dir; - int fdir; - int fd; - - fdir = igt_debugfs_dir(drm_fd); - if (fdir < 0) - return; - - dir = fdopendir(fdir); - if (!dir) { - close(fdir); - return; - } - - while ((dirent = readdir(dir))) { - char buf[128]; - - if (strcmp(dirent->d_name, "crtc-") != 0) - continue; - - sprintf(buf, "%s/crc/control", dirent->d_name); - fd = openat(fdir, buf, O_WRONLY); - if (fd < 0) - continue; - - igt_assert_eq(write(fd, cmd, strlen(cmd)), strlen(cmd)); - close(fd); - - done = true; - } - closedir(dir); - - if (!done) { - fd = openat(fdir, "i915_display_crtc_ctl", O_WRONLY); - if (fd != -1) { - igt_pipe_crc_pipe_off(fd, PIPE_A); - igt_pipe_crc_pipe_off(fd, PIPE_B); - igt_pipe_crc_pipe_off(fd, PIPE_C); - - close(fd); - } - } - - close(fdir); -} - -static void pipe_crc_exit_handler(int sig) -{ - struct dirent *dirent; - char buf[128]; - DIR *dir; - int fd; - - dir = opendir("/dev/dri"); - if (!dir) - return; - - /* - * Try to reset CRC capture for all DRM devices, this is only needed - * for the legacy CRC ABI and can be completely removed once the - * legacy codepaths are removed. - */ - while ((dirent = readdir(dir))) { - if (strncmp(dirent->d_name, "card", 4) != 0) - continue; - - sprintf(buf, "/dev/dri/%s", dirent->d_name); - fd = open(buf, O_WRONLY); - - igt_pipe_crc_reset(fd); - - close(fd); - } - closedir(dir); -} - -/** - * igt_require_pipe_crc: - * - * Convenience helper to check whether pipe CRC capturing is supported by the - * kernel. Uses igt_skip to automatically skip the test/subtest if this isn't - * the case. - */ -void igt_require_pipe_crc(int fd) -{ - const char *cmd = "pipe A none"; - int ctl, written; - - ctl = igt_debugfs_open(fd, "crtc-0/crc/control", O_RDONLY); - if (ctl < 0) { - ctl = igt_debugfs_open(fd, "i915_display_crc_ctl", O_WRONLY); - igt_require_f(ctl, - "No display_crc_ctl found, kernel too old\n"); - - written = write(ctl, cmd, strlen(cmd)); - igt_require_f(written < 0, - "CRCs not supported on this platform\n"); - } - close(ctl); -} - static void igt_hpd_storm_exit_handler(int sig) { int fd = drm_open_driver_master(DRIVER_INTEL); @@ -627,306 +380,6 @@ void igt_require_hpd_storm_ctl(int drm_fd) close(fd); } -static igt_pipe_crc_t * -pipe_crc_new(int fd, enum pipe pipe, enum intel_pipe_crc_source source, int flags) -{ - igt_pipe_crc_t *pipe_crc; - char buf[128]; - int debugfs; - - debugfs = igt_debugfs_dir(fd); - igt_assert(debugfs != -1); - - igt_install_exit_handler(pipe_crc_exit_handler); - - pipe_crc = calloc(1, sizeof(struct _igt_pipe_crc)); - - sprintf(buf, "crtc-%d/crc/control", pipe); - pipe_crc->ctl_fd = openat(debugfs, buf, O_WRONLY); - if (pipe_crc->ctl_fd == -1) { - pipe_crc->ctl_fd = openat(debugfs, - "i915_display_crc_ctl", O_WRONLY); - igt_assert(pipe_crc->ctl_fd != -1); - pipe_crc->is_legacy = true; - } - - if (pipe_crc->is_legacy) { - sprintf(buf, "i915_pipe_%s_crc", kmstest_pipe_name(pipe)); - pipe_crc->crc_fd = openat(debugfs, buf, flags); - igt_assert(pipe_crc->crc_fd != -1); - igt_debug("Using legacy frame CRC ABI\n"); - } else { - pipe_crc->crc_fd = -1; - igt_debug("Using generic frame CRC ABI\n"); - } - - pipe_crc->fd = fd; - pipe_crc->dir = debugfs; - pipe_crc->pipe = pipe; - pipe_crc->source = source; - pipe_crc->flags = flags; - - return pipe_crc; -} - -/** - * igt_pipe_crc_new: - * @pipe: display pipe to use as source - * @source: CRC tap point to use as source - * - * This sets up a new pipe CRC capture object for the given @pipe and @source - * in blocking mode. - * - * Returns: A pipe CRC object for the given @pipe and @source. The library - * assumes that the source is always available since recent kernels support at - * least INTEL_PIPE_CRC_SOURCE_AUTO everywhere. - */ -igt_pipe_crc_t * -igt_pipe_crc_new(int fd, enum pipe pipe, enum intel_pipe_crc_source source) -{ - return pipe_crc_new(fd, pipe, source, O_RDONLY); -} - -/** - * igt_pipe_crc_new_nonblock: - * @pipe: display pipe to use as source - * @source: CRC tap point to use as source - * - * This sets up a new pipe CRC capture object for the given @pipe and @source - * in nonblocking mode. - * - * Returns: A pipe CRC object for the given @pipe and @source. The library - * assumes that the source is always available since recent kernels support at - * least INTEL_PIPE_CRC_SOURCE_AUTO everywhere. - */ -igt_pipe_crc_t * -igt_pipe_crc_new_nonblock(int fd, enum pipe pipe, enum intel_pipe_crc_source source) -{ - return pipe_crc_new(fd, pipe, source, O_RDONLY | O_NONBLOCK); -} - -/** - * igt_pipe_crc_free: - * @pipe_crc: pipe CRC object - * - * Frees all resources associated with @pipe_crc. - */ -void igt_pipe_crc_free(igt_pipe_crc_t *pipe_crc) -{ - if (!pipe_crc) - return; - - close(pipe_crc->ctl_fd); - close(pipe_crc->crc_fd); - close(pipe_crc->dir); - free(pipe_crc); -} - -static bool pipe_crc_init_from_string(igt_pipe_crc_t *pipe_crc, igt_crc_t *crc, - const char *line) -{ - int n, i; - const char *buf; - - if (pipe_crc->is_legacy) { - crc->has_valid_frame = true; - crc->n_words = 5; - n = sscanf(line, "%8u %8x %8x %8x %8x %8x", &crc->frame, - &crc->crc[0], &crc->crc[1], &crc->crc[2], - &crc->crc[3], &crc->crc[4]); - return n == 6; - } - - if (strncmp(line, "XXXXXXXXXX", 10) == 0) - crc->has_valid_frame = false; - else { - crc->has_valid_frame = true; - crc->frame = strtoul(line, NULL, 16); - } - - buf = line + 10; - for (i = 0; *buf != '\n'; i++, buf += 11) - crc->crc[i] = strtoul(buf, NULL, 16); - - crc->n_words = i; - - return true; -} - -static int read_crc(igt_pipe_crc_t *pipe_crc, igt_crc_t *out) -{ - ssize_t bytes_read; - char buf[MAX_LINE_LEN + 1]; - size_t read_len; - - if (pipe_crc->is_legacy) - read_len = LEGACY_LINE_LEN; - else - read_len = MAX_LINE_LEN; - - igt_set_timeout(5, "CRC reading"); - bytes_read = read(pipe_crc->crc_fd, &buf, read_len); - igt_reset_timeout(); - - if (bytes_read < 0 && errno == EAGAIN) - igt_assert(pipe_crc->flags & O_NONBLOCK); - - if (bytes_read < 0) - bytes_read = 0; - - buf[bytes_read] = '\0'; - - if (bytes_read && !pipe_crc_init_from_string(pipe_crc, out, buf)) - return -EINVAL; - - return bytes_read; -} - -static void read_one_crc(igt_pipe_crc_t *pipe_crc, igt_crc_t *out) -{ - while (read_crc(pipe_crc, out) == 0) - usleep(1000); -} - -/** - * igt_pipe_crc_start: - * @pipe_crc: pipe CRC object - * - * Starts the CRC capture process on @pipe_crc. - */ -void igt_pipe_crc_start(igt_pipe_crc_t *pipe_crc) -{ - igt_crc_t crc; - - igt_assert(igt_pipe_crc_do_start(pipe_crc)); - - if (pipe_crc->is_legacy) { - /* - * For some no yet identified reason, the first CRC is - * bonkers. So let's just wait for the next vblank and read - * out the buggy result. - * - * On CHV sometimes the second CRC is bonkers as well, so - * don't trust that one either. - */ - read_one_crc(pipe_crc, &crc); - read_one_crc(pipe_crc, &crc); - } -} - -/** - * igt_pipe_crc_stop: - * @pipe_crc: pipe CRC object - * - * Stops the CRC capture process on @pipe_crc. - */ -void igt_pipe_crc_stop(igt_pipe_crc_t *pipe_crc) -{ - char buf[32]; - - if (pipe_crc->is_legacy) { - sprintf(buf, "pipe %s none", kmstest_pipe_name(pipe_crc->pipe)); - igt_assert_eq(write(pipe_crc->ctl_fd, buf, strlen(buf)), - strlen(buf)); - } else { - close(pipe_crc->crc_fd); - pipe_crc->crc_fd = -1; - } -} - -/** - * igt_pipe_crc_get_crcs: - * @pipe_crc: pipe CRC object - * @n_crcs: number of CRCs to capture - * @out_crcs: buffer pointer for the captured CRC values - * - * Read up to @n_crcs from @pipe_crc. This function does not block, and will - * return early if not enough CRCs can be captured, if @pipe_crc has been - * opened using igt_pipe_crc_new_nonblock(). It will block until @n_crcs are - * retrieved if @pipe_crc has been opened using igt_pipe_crc_new(). @out_crcs is - * alloced by this function and must be released with free() by the caller. - * - * Callers must start and stop the capturing themselves by calling - * igt_pipe_crc_start() and igt_pipe_crc_stop(). For one-shot CRC collecting - * look at igt_pipe_crc_collect_crc(). - * - * Returns: - * The number of CRCs captured. Should be equal to @n_crcs in blocking mode, but - * can be less (even zero) in non-blocking mode. - */ -int -igt_pipe_crc_get_crcs(igt_pipe_crc_t *pipe_crc, int n_crcs, - igt_crc_t **out_crcs) -{ - igt_crc_t *crcs; - int n = 0; - - crcs = calloc(n_crcs, sizeof(igt_crc_t)); - - do { - igt_crc_t *crc = &crcs[n]; - int ret; - - ret = read_crc(pipe_crc, crc); - if (ret < 0) - continue; - if (ret == 0) - break; - - n++; - } while (n < n_crcs); - - *out_crcs = crcs; - return n; -} - -static void crc_sanity_checks(igt_crc_t *crc) -{ - int i; - bool all_zero = true; - - for (i = 0; i < crc->n_words; i++) { - igt_warn_on_f(crc->crc[i] == 0xffffffff, - "Suspicious CRC: it looks like the CRC " - "read back was from a register in a powered " - "down well\n"); - if (crc->crc[i]) - all_zero = false; - } - - igt_warn_on_f(all_zero, "Suspicious CRC: All values are 0.\n"); -} - -/** - * igt_pipe_crc_collect_crc: - * @pipe_crc: pipe CRC object - * @out_crc: buffer for the captured CRC values - * - * Read a single CRC from @pipe_crc. This function blocks until the CRC is - * retrieved, irrespective of whether @pipe_crc has been opened with - * igt_pipe_crc_new() or igt_pipe_crc_new_nonblock(). @out_crc must be - * allocated by the caller. - * - * This function takes care of the pipe_crc book-keeping, it will start/stop - * the collection of the CRC. - * - * This function also calls the interactive debug with the "crc" domain, so you - * can make use of this feature to actually see the screen that is being CRC'd. - * - * For continuous CRC collection look at igt_pipe_crc_start(), - * igt_pipe_crc_get_crcs() and igt_pipe_crc_stop(). - */ -void igt_pipe_crc_collect_crc(igt_pipe_crc_t *pipe_crc, igt_crc_t *out_crc) -{ - igt_debug_wait_for_keypress("crc"); - - igt_pipe_crc_start(pipe_crc); - read_one_crc(pipe_crc, out_crc); - igt_pipe_crc_stop(pipe_crc); - - crc_sanity_checks(out_crc); -} - /* * Drop caches */ diff --git a/lib/igt_debugfs.h b/lib/igt_debugfs.h index 7b846a83..01a5ee07 100644 --- a/lib/igt_debugfs.h +++ b/lib/igt_debugfs.h @@ -29,8 +29,6 @@ #include #include -enum pipe; - const char *igt_debugfs_mount(void); int igt_debugfs_dir(int device); @@ -50,85 +48,6 @@ bool igt_debugfs_search(int fd, const char *filename, const char *substring); #define igt_debugfs_read(fd, filename, buf) \ __igt_debugfs_read(fd, (filename), (buf), sizeof(buf)) -/* - * Pipe CRC - */ - -/** - * igt_pipe_crc_t: - * - * Pipe CRC support structure. Needs to be allocated and set up with - * igt_pipe_crc_new() for a specific pipe and pipe CRC source value. - */ -typedef struct _igt_pipe_crc igt_pipe_crc_t; - -#define DRM_MAX_CRC_NR 10 -/** - * igt_crc_t: - * @frame: frame number of the capture CRC - * @n_words: internal field, don't access - * @crc: internal field, don't access - * - * Pipe CRC value. All other members than @frame are private and should not be - * inspected by testcases. - */ -typedef struct { - uint32_t frame; - bool has_valid_frame; - int n_words; - uint32_t crc[DRM_MAX_CRC_NR]; -} igt_crc_t; - -/** - * intel_pipe_crc_source: - * @INTEL_PIPE_CRC_SOURCE_NONE: No source - * @INTEL_PIPE_CRC_SOURCE_PLANE1: Plane 1 - * @INTEL_PIPE_CRC_SOURCE_PLANE2: Plane 2 - * @INTEL_PIPE_CRC_SOURCE_PF: Panel Filter - * @INTEL_PIPE_CRC_SOURCE_PIPE: Pipe - * @INTEL_PIPE_CRC_SOURCE_TV: TV - * @INTEL_PIPE_CRC_SOURCE_DP_B: DisplayPort B - * @INTEL_PIPE_CRC_SOURCE_DP_C: DisplayPort C - * @INTEL_PIPE_CRC_SOURCE_DP_D: DisplayPort D - * @INTEL_PIPE_CRC_SOURCE_AUTO: Automatic source selection - * @INTEL_PIPE_CRC_SOURCE_MAX: Number of available sources - * - * Enumeration of all supported pipe CRC sources. Not all platforms and all - * outputs support all of them. Generic tests should just use - * INTEL_PIPE_CRC_SOURCE_AUTO. It should always map to an end-of-pipe CRC - * suitable for checking planes, cursor, color correction and any other - * output-agnostic features. - */ -enum intel_pipe_crc_source { - INTEL_PIPE_CRC_SOURCE_NONE, - INTEL_PIPE_CRC_SOURCE_PLANE1, - INTEL_PIPE_CRC_SOURCE_PLANE2, - INTEL_PIPE_CRC_SOURCE_PF, - INTEL_PIPE_CRC_SOURCE_PIPE, - INTEL_PIPE_CRC_SOURCE_TV, - INTEL_PIPE_CRC_SOURCE_DP_B, - INTEL_PIPE_CRC_SOURCE_DP_C, - INTEL_PIPE_CRC_SOURCE_DP_D, - INTEL_PIPE_CRC_SOURCE_AUTO, - INTEL_PIPE_CRC_SOURCE_MAX, -}; - -void igt_assert_crc_equal(const igt_crc_t *a, const igt_crc_t *b); -char *igt_crc_to_string(igt_crc_t *crc); - -void igt_require_pipe_crc(int fd); -igt_pipe_crc_t * -igt_pipe_crc_new(int fd, enum pipe pipe, enum intel_pipe_crc_source source); -igt_pipe_crc_t * -igt_pipe_crc_new_nonblock(int fd, enum pipe pipe, enum intel_pipe_crc_source source); -void igt_pipe_crc_free(igt_pipe_crc_t *pipe_crc); -void igt_pipe_crc_start(igt_pipe_crc_t *pipe_crc); -void igt_pipe_crc_stop(igt_pipe_crc_t *pipe_crc); -__attribute__((warn_unused_result)) -int igt_pipe_crc_get_crcs(igt_pipe_crc_t *pipe_crc, int n_crcs, - igt_crc_t **out_crcs); -void igt_pipe_crc_collect_crc(igt_pipe_crc_t *pipe_crc, igt_crc_t *out_crc); - void igt_hpd_storm_set_threshold(int fd, unsigned int threshold); void igt_hpd_storm_reset(int fd); bool igt_hpd_storm_detected(int fd); diff --git a/tests/chamelium.c b/tests/chamelium.c index e26f0557..5482eb5b 100644 --- a/tests/chamelium.c +++ b/tests/chamelium.c @@ -26,6 +26,7 @@ #include "config.h" #include "igt.h" +#include "igt_crc.h" #include #include diff --git a/tests/kms_atomic_transition.c b/tests/kms_atomic_transition.c index e22763bd..1b9233ad 100644 --- a/tests/kms_atomic_transition.c +++ b/tests/kms_atomic_transition.c @@ -22,6 +22,7 @@ */ #include "igt.h" +#include "igt_crc.h" #include "drmtest.h" #include "sw_sync.h" #include diff --git a/tests/kms_ccs.c b/tests/kms_ccs.c index 29d676af..66bd0f29 100644 --- a/tests/kms_ccs.c +++ b/tests/kms_ccs.c @@ -23,6 +23,7 @@ */ #include "igt.h" +#include "igt_crc.h" IGT_TEST_DESCRIPTION("Test render compression (RC), in which the main surface " "is complemented by a color control surface (CCS) that " diff --git a/tests/kms_chv_cursor_fail.c b/tests/kms_chv_cursor_fail.c index 3e74df11..b02958bd 100644 --- a/tests/kms_chv_cursor_fail.c +++ b/tests/kms_chv_cursor_fail.c @@ -23,6 +23,7 @@ */ #include "igt.h" +#include "igt_crc.h" #include #include #include diff --git a/tests/kms_crtc_background_color.c b/tests/kms_crtc_background_color.c index e12e1634..3bcabcac 100644 --- a/tests/kms_crtc_background_color.c +++ b/tests/kms_crtc_background_color.c @@ -23,6 +23,7 @@ */ #include "igt.h" +#include "igt_crc.h" #include diff --git a/tests/kms_cursor_crc.c b/tests/kms_cursor_crc.c index 4c5e00c0..4693e9f4 100644 --- a/tests/kms_cursor_crc.c +++ b/tests/kms_cursor_crc.c @@ -23,6 +23,7 @@ */ #include "igt.h" +#include "igt_crc.h" #include #include #include diff --git a/tests/kms_cursor_legacy.c b/tests/kms_cursor_legacy.c index 8180b043..505e3f9d 100644 --- a/tests/kms_cursor_legacy.c +++ b/tests/kms_cursor_legacy.c @@ -27,6 +27,7 @@ #include #include "igt.h" +#include "igt_crc.h" #include "igt_rand.h" #include "igt_stats.h" diff --git a/tests/kms_draw_crc.c b/tests/kms_draw_crc.c index c57d3a35..8cb4e147 100644 --- a/tests/kms_draw_crc.c +++ b/tests/kms_draw_crc.c @@ -25,6 +25,7 @@ /* This program tests whether the igt_draw library actually works. */ #include "igt.h" +#include "igt_crc.h" #define MAX_CONNECTORS 32 diff --git a/tests/kms_fbc_crc.c b/tests/kms_fbc_crc.c index 7964e052..10656b89 100644 --- a/tests/kms_fbc_crc.c +++ b/tests/kms_fbc_crc.c @@ -23,6 +23,7 @@ */ #include "igt.h" +#include "igt_crc.h" #include #include #include diff --git a/tests/kms_flip_tiling.c b/tests/kms_flip_tiling.c index 5aae29a8..8e1a2fb4 100644 --- a/tests/kms_flip_tiling.c +++ b/tests/kms_flip_tiling.c @@ -25,6 +25,7 @@ */ #include "igt.h" +#include "igt_crc.h" #include #include #include diff --git a/tests/kms_frontbuffer_tracking.c b/tests/kms_frontbuffer_tracking.c index e03524f1..c1b08669 100644 --- a/tests/kms_frontbuffer_tracking.c +++ b/tests/kms_frontbuffer_tracking.c @@ -25,6 +25,7 @@ */ #include "igt.h" +#include "igt_crc.h" #include "igt_sysfs.h" #include #include diff --git a/tests/kms_mmap_write_crc.c b/tests/kms_mmap_write_crc.c index e5f089f6..79efa792 100644 --- a/tests/kms_mmap_write_crc.c +++ b/tests/kms_mmap_write_crc.c @@ -31,6 +31,7 @@ #include #include "drmtest.h" +#include "igt_crc.h" #include "igt_debugfs.h" #include "igt_kms.h" #include "intel_chipset.h" diff --git a/tests/kms_mmio_vs_cs_flip.c b/tests/kms_mmio_vs_cs_flip.c index fa947d9c..ee1d202a 100644 --- a/tests/kms_mmio_vs_cs_flip.c +++ b/tests/kms_mmio_vs_cs_flip.c @@ -22,6 +22,7 @@ */ #include "igt.h" +#include "igt_crc.h" #include #include #include diff --git a/tests/kms_pipe_color.c b/tests/kms_pipe_color.c index a3100fae..389fb3de 100644 --- a/tests/kms_pipe_color.c +++ b/tests/kms_pipe_color.c @@ -28,6 +28,7 @@ #include "drm.h" #include "drmtest.h" #include "igt.h" +#include "igt_crc.h" IGT_TEST_DESCRIPTION("Test Color Features at Pipe level"); diff --git a/tests/kms_pipe_crc_basic.c b/tests/kms_pipe_crc_basic.c index 35adddba..38da3a42 100644 --- a/tests/kms_pipe_crc_basic.c +++ b/tests/kms_pipe_crc_basic.c @@ -23,6 +23,7 @@ */ #include "igt.h" +#include "igt_crc.h" #include "igt_sysfs.h" #include #include diff --git a/tests/kms_plane.c b/tests/kms_plane.c index 1d92a62b..2fa58e8f 100644 --- a/tests/kms_plane.c +++ b/tests/kms_plane.c @@ -25,6 +25,7 @@ */ #include "igt.h" +#include "igt_crc.h" #include #include #include diff --git a/tests/kms_plane_lowres.c b/tests/kms_plane_lowres.c index ee39759c..a4e37275 100644 --- a/tests/kms_plane_lowres.c +++ b/tests/kms_plane_lowres.c @@ -23,6 +23,7 @@ */ #include "igt.h" +#include "igt_crc.h" #include "drmtest.h" #include #include diff --git a/tests/kms_plane_multiple.c b/tests/kms_plane_multiple.c index f6c62235..1b60a067 100644 --- a/tests/kms_plane_multiple.c +++ b/tests/kms_plane_multiple.c @@ -23,6 +23,7 @@ */ #include "igt.h" +#include "igt_crc.h" #include "drmtest.h" #include #include diff --git a/tests/kms_plane_scaling.c b/tests/kms_plane_scaling.c index 1457894a..d554f27f 100644 --- a/tests/kms_plane_scaling.c +++ b/tests/kms_plane_scaling.c @@ -23,6 +23,7 @@ */ #include "igt.h" +#include "igt_crc.h" #include diff --git a/tests/kms_pwrite_crc.c b/tests/kms_pwrite_crc.c index ee895db6..f1e6f023 100644 --- a/tests/kms_pwrite_crc.c +++ b/tests/kms_pwrite_crc.c @@ -23,6 +23,7 @@ */ #include "igt.h" +#include "igt_crc.h" #include #include #include diff --git a/tests/kms_rotation_crc.c b/tests/kms_rotation_crc.c index 83e37f12..fa361100 100644 --- a/tests/kms_rotation_crc.c +++ b/tests/kms_rotation_crc.c @@ -23,6 +23,7 @@ */ #include "igt.h" +#include "igt_crc.h" #include #define MAX_FENCES 32 diff --git a/tests/kms_universal_plane.c b/tests/kms_universal_plane.c index 31f07804..14300b7a 100644 --- a/tests/kms_universal_plane.c +++ b/tests/kms_universal_plane.c @@ -22,6 +22,7 @@ */ #include "igt.h" +#include "igt_crc.h" #include #include #include diff --git a/tools/intel_display_crc.c b/tools/intel_display_crc.c index d1b28ea7..104f432f 100644 --- a/tools/intel_display_crc.c +++ b/tools/intel_display_crc.c @@ -30,6 +30,7 @@ #include #include "igt_core.h" +#include "igt_crc.h" #include "igt_debugfs.h" #include "igt_kms.h" From patchwork Fri Jul 14 15:18:51 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Liviu Dudau X-Patchwork-Id: 107807 Delivered-To: patch@linaro.org Received: by 10.140.101.44 with SMTP id t41csp1034416qge; Fri, 14 Jul 2017 08:19:22 -0700 (PDT) X-Received: by 10.98.217.145 with SMTP id b17mr5938587pfl.70.1500045562305; Fri, 14 Jul 2017 08:19:22 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1500045562; cv=none; d=google.com; s=arc-20160816; b=FsFQoym1I52W4ovdyFHLkR3mjM+Z6zeUPE2n4tkJKv6qNCa46vDFrkUkoHQ8ohZzzf Cvp9MHALOz8Zl2movCCMsnLOWRuty2QqFIoF+CepGLoQJAQLdpBRSrkuAPzvHkrXKfOD waKGgHpDVVwx06TO/hMsHwA+F4qU3VHtxjlCSBcPY/hAeL9NQ0q7MEKK5rM+cIWqVjgV lvZjhd6/Y2xS9x0Xs9gBM/7PfG1+zn3AmxLfLC8gbPH8o7t4m4/n+5LQVOhO+PgOjWNQ UKcWmwczTHLBUrmWMrAMwhvfOafxIZVMPGeXJcxrkxRQwDcslajSHpzB9K229PcPdc2A UE8Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:cc:references:in-reply-to:message-id:date :subject:to:from:delivered-to:arc-authentication-results; bh=NGQU+aWxeQVyNPN+dcOVPQTuQ/ak9NezeTJ0J4xqcJE=; b=ayZi+uEQsKuDw/mXeeOMk29nOvJ1acmJ9oVT2180kqYyVP3oWeKHfLIUWJyjSEBa44 xnASfyq+P3xjPJlIxCKWwK/9RVNnVpIdS+LkEToHqXqmZi+h09Vw2Fb2ffgUoOeSUGKe 7ubxlJAkIcWLkCjuwDUIzGsKpxhKJWQCVzlYyRrIhLqq+bC0YHDEOAWLr0v916hHc6jw pAyzOSaRGaAHPMPAPtDhOXbaZFTU3I3BIXrKrGXDUBcTTCLdvk71G9c3PTWXEOpmCJlO yOT+SownA1zXtI1VbmDK+r8KWmi8lsok42ufQ3ezUQObqNqsQ1pE0SM3bh8Ej9nYhMfE D8cA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of dri-devel-bounces@lists.freedesktop.org designates 131.252.210.177 as permitted sender) smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Return-Path: Received: from gabe.freedesktop.org (gabe.freedesktop.org. [131.252.210.177]) by mx.google.com with ESMTPS id a25si6812175pgn.241.2017.07.14.08.19.22 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 14 Jul 2017 08:19:22 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of dri-devel-bounces@lists.freedesktop.org designates 131.252.210.177 as permitted sender) client-ip=131.252.210.177; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of dri-devel-bounces@lists.freedesktop.org designates 131.252.210.177 as permitted sender) smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 9436F6E87A; Fri, 14 Jul 2017 15:19:07 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from cam-smtp0.cambridge.arm.com (fw-tnat.cambridge.arm.com [217.140.96.140]) by gabe.freedesktop.org (Postfix) with ESMTPS id C39466E86F; Fri, 14 Jul 2017 15:19:01 +0000 (UTC) Received: from e110455-lin.cambridge.arm.com (e110455-lin.cambridge.arm.com [10.2.131.9]) by cam-smtp0.cambridge.arm.com (8.13.8/8.13.8) with ESMTP id v6EFIuFL000867; Fri, 14 Jul 2017 16:18:56 +0100 From: Liviu Dudau To: Intel GFX discussion Subject: [PATCH i-g-t v2 2/7] lib/igt_kms: Add writeback support in lib/ Date: Fri, 14 Jul 2017 16:18:51 +0100 Message-Id: <20170714151856.32041-3-liviu.dudau@arm.com> X-Mailer: git-send-email 2.13.2 In-Reply-To: <20170714151856.32041-1-liviu.dudau@arm.com> References: <20170714151856.32041-1-liviu.dudau@arm.com> Cc: Boris Brezillon , DRI devel X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" From: Brian Starkey Add support in igt_kms for Writeback connectors, with the ability to attach framebuffers and retrieve fences. Signed-off-by: Brian Starkey --- lib/igt_aux.c | 1 + lib/igt_kms.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- lib/igt_kms.h | 16 +++++++++++++ 3 files changed, 92 insertions(+), 1 deletion(-) diff --git a/lib/igt_aux.c b/lib/igt_aux.c index 86a213c2..ad80452a 100644 --- a/lib/igt_aux.c +++ b/lib/igt_aux.c @@ -1106,6 +1106,7 @@ static const struct type_name connector_type_names[] = { { DRM_MODE_CONNECTOR_eDP, "eDP" }, { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" }, { DRM_MODE_CONNECTOR_DSI, "DSI" }, + { DRM_MODE_CONNECTOR_WRITEBACK, "Writeback" }, {} }; diff --git a/lib/igt_kms.c b/lib/igt_kms.c index 6390229f..02e2b274 100644 --- a/lib/igt_kms.c +++ b/lib/igt_kms.c @@ -186,7 +186,10 @@ const char *igt_crtc_prop_names[IGT_NUM_CRTC_PROPS] = { const char *igt_connector_prop_names[IGT_NUM_CONNECTOR_PROPS] = { "scaling mode", - "CRTC_ID" + "CRTC_ID", + "WRITEBACK_PIXEL_FORMATS", + "WRITEBACK_FB_ID", + "WRITEBACK_OUT_FENCE_PTR" }; /* @@ -1832,6 +1835,7 @@ void igt_display_init(igt_display_t *display, int drm_fd) output->pending_crtc_idx_mask = 0; output->id = resources->connectors[i]; output->display = display; + output->writeback_out_fence_fd = -1; igt_output_refresh(output); @@ -1899,6 +1903,42 @@ igt_output_t *igt_output_from_connector(igt_display_t *display, return found; } +void igt_output_set_writeback_fb(igt_output_t *output, struct igt_fb *fb) +{ + igt_display_t *display = output->display; + struct kmstest_connector_config *config = &output->config; + + if (config->connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) + return; + + LOG(display, "%s: output_set_writeback_fb(%d)\n", output->name, + fb ? fb->fb_id : 0); + + output->writeback_fb = fb; +} + +static void igt_output_reset_writeback_out_fence(igt_output_t *output) +{ + if (output->writeback_out_fence_fd >= 0) { + close(output->writeback_out_fence_fd); + output->writeback_out_fence_fd = -1; + } +} + +void igt_output_request_writeback_out_fence(igt_output_t *output) +{ + igt_output_reset_writeback_out_fence(output); + output->writeback_out_fence_requested = true; +} + +int igt_output_get_last_writeback_out_fence(igt_output_t *output) +{ + int fd = output->writeback_out_fence_fd; + output->writeback_out_fence_fd = -1; + + return fd; +} + static void igt_pipe_fini(igt_pipe_t *pipe) { int i; @@ -1922,6 +1962,8 @@ static void igt_pipe_fini(igt_pipe_t *pipe) static void igt_output_fini(igt_output_t *output) { kmstest_free_connector_config(&output->config); + if (output->writeback_out_fence_fd >= 0) + close(output->writeback_out_fence_fd); free(output->name); output->name = NULL; } @@ -2541,10 +2583,41 @@ static void igt_atomic_prepare_connector_commit(igt_output_t *output, drmModeAto igt_atomic_populate_connector_req(req, output, IGT_CONNECTOR_CRTC_ID, crtc_id); } + + if (output->writeback_fb) { + igt_atomic_populate_connector_req(req, output, IGT_CONNECTOR_WRITEBACK_FB_ID, output->writeback_fb->fb_id); + output->writeback_fb = NULL; + } + + igt_output_reset_writeback_out_fence(output); + if (output->writeback_out_fence_requested) { + igt_atomic_populate_connector_req(req, output, IGT_CONNECTOR_WRITEBACK_OUT_FENCE_PTR, + (uint64_t)(uintptr_t)&output->writeback_out_fence_fd); + } + /* * TODO: Add all other connector level properties here */ +} + +static void handle_writeback_out_fences(igt_display_t *display, uint32_t flags, int ret) +{ + int i; + for (i = 0; i < display->n_outputs; i++) { + igt_output_t *output = &display->outputs[i]; + + if (!output->config.connector) + continue; + + if (!output->writeback_out_fence_requested) + continue; + + output->writeback_out_fence_requested = false; + + if (ret || (flags & DRM_MODE_ATOMIC_TEST_ONLY)) + igt_assert(output->writeback_out_fence_fd == -1); + } } /* @@ -2593,6 +2666,7 @@ static int igt_atomic_commit(igt_display_t *display, uint32_t flags, void *user_ } ret = drmModeAtomicCommit(display->drm_fd, req, flags, user_data); + handle_writeback_out_fences(display, flags, ret); drmModeAtomicFree(req); return ret; diff --git a/lib/igt_kms.h b/lib/igt_kms.h index 35428f3e..ce9a35ef 100644 --- a/lib/igt_kms.h +++ b/lib/igt_kms.h @@ -37,6 +37,10 @@ #include "igt_fb.h" #include "ioctl_wrappers.h" +#ifndef DRM_MODE_CONNECTOR_WRITEBACK +#define DRM_MODE_CONNECTOR_WRITEBACK 18 +#endif + /* Low-level helpers with kmstest_ prefix */ /** @@ -113,6 +117,9 @@ extern const char *igt_crtc_prop_names[]; enum igt_atomic_connector_properties { IGT_CONNECTOR_SCALING_MODE = 0, IGT_CONNECTOR_CRTC_ID, + IGT_CONNECTOR_WRITEBACK_PIXEL_FORMATS, + IGT_CONNECTOR_WRITEBACK_FB_ID, + IGT_CONNECTOR_WRITEBACK_OUT_FENCE_PTR, IGT_NUM_CONNECTOR_PROPS }; @@ -363,6 +370,10 @@ typedef struct { unsigned long pending_crtc_idx_mask; bool use_override_mode; drmModeModeInfo override_mode; + + struct igt_fb *writeback_fb; + int32_t writeback_out_fence_fd; + bool writeback_out_fence_requested; } igt_output_t; struct igt_display { @@ -392,10 +403,15 @@ drmModeModeInfo *igt_output_get_mode(igt_output_t *output); void igt_output_override_mode(igt_output_t *output, drmModeModeInfo *mode); void igt_output_set_pipe(igt_output_t *output, enum pipe pipe); void igt_output_set_scaling_mode(igt_output_t *output, uint64_t scaling_mode); + igt_plane_t *igt_output_get_plane(igt_output_t *output, int plane_idx); igt_plane_t *igt_output_get_plane_type(igt_output_t *output, int plane_type); igt_output_t *igt_output_from_connector(igt_display_t *display, drmModeConnector *connector); +void igt_output_set_writeback_fb(igt_output_t *output, struct igt_fb *fb); +void igt_output_request_writeback_out_fence(igt_output_t *output); +int igt_output_get_last_writeback_out_fence(igt_output_t *output); + igt_plane_t *igt_pipe_get_plane_type(igt_pipe_t *pipe, int plane_type); bool igt_pipe_get_property(igt_pipe_t *pipe, const char *name, uint32_t *prop_id, uint64_t *value, From patchwork Fri Jul 14 15:18:52 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Liviu Dudau X-Patchwork-Id: 107809 Delivered-To: patch@linaro.org Received: by 10.140.101.44 with SMTP id t41csp1034870qge; Fri, 14 Jul 2017 08:19:47 -0700 (PDT) X-Received: by 10.98.96.66 with SMTP id u63mr5943126pfb.68.1500045587113; Fri, 14 Jul 2017 08:19:47 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1500045587; cv=none; d=google.com; s=arc-20160816; b=uGD4f5GQC+RZIHWCL4RAkvXEli5EcKabhKPELfGhY8TWAmJFzvR3hxSny17QrdwWn+ cZ7vKn2DulEGSLb/h58YXIr0HWrajcV68LlB0Qxs72dTkpPjQUwenfeEPjteEBBLyUWz 1aHsCwplAqWjmOntoePR3MSxlVqNczrXv5nXmlS2geJs8PP677GhKcihhOekesO9EHRo X4pBSthC21onzU+elkkmGZVC5Js8whSmjs/Ez5FTBwNAExfCGFaN12CodDTB/d0OgO1e 82SYXlbVYSlscRvuTA8yXH0C0aJh5xgz7oninH8W8uYMp8tpEUgGAftx04xaquNKWozc 7B5g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:cc:references:in-reply-to:message-id:date :subject:to:from:delivered-to:arc-authentication-results; bh=JClveXiGxaaYQgjV+QG2AX7+KOxodBYVjB8NoNI2zcI=; b=JlkRYyJWyhUH3T1b85FPTxoLJc8UjzFbG50Af2w+mlcFVxuO1WfodrS1pQiGSHxHGf Z9lHfMGeFoNsVjYCrlrkK1kK6eEpVil1sTyj3nZ7vzT7Mr8j6TDRFVCYTb1BDQsqq9Nx GkgrGISt67QuhcquPb4RnLq6HlKKFLFkfmQNIasBnTUp+GKvo4tVOfV4tnC9JPzhVLi7 qGcbMezZyVJ9rg3Pnu335bSNeSloSsHHxOVrX7bBFPZopo+AEcIL5dMwCLJo57BNKrmq gq3QXc8l7a7L88ehIiDfZvrtcoWfO9S5Yi/0D0FWaM4Oy6k4jXiqpktbRdhnrigPRHRt 3YBA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of dri-devel-bounces@lists.freedesktop.org designates 131.252.210.177 as permitted sender) smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Return-Path: Received: from gabe.freedesktop.org (gabe.freedesktop.org. [131.252.210.177]) by mx.google.com with ESMTPS id b14si7024963plk.566.2017.07.14.08.19.46 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 14 Jul 2017 08:19:47 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of dri-devel-bounces@lists.freedesktop.org designates 131.252.210.177 as permitted sender) client-ip=131.252.210.177; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of dri-devel-bounces@lists.freedesktop.org designates 131.252.210.177 as permitted sender) smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id E3D396E88D; Fri, 14 Jul 2017 15:19:09 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from cam-smtp0.cambridge.arm.com (fw-tnat.cambridge.arm.com [217.140.96.140]) by gabe.freedesktop.org (Postfix) with ESMTPS id DA3AF6E871; Fri, 14 Jul 2017 15:19:01 +0000 (UTC) Received: from e110455-lin.cambridge.arm.com (e110455-lin.cambridge.arm.com [10.2.131.9]) by cam-smtp0.cambridge.arm.com (8.13.8/8.13.8) with ESMTP id v6EFIuFM000867; Fri, 14 Jul 2017 16:18:57 +0100 From: Liviu Dudau To: Intel GFX discussion Subject: [PATCH i-g-t v2 3/7] kms_writeback: Add initial writeback tests Date: Fri, 14 Jul 2017 16:18:52 +0100 Message-Id: <20170714151856.32041-4-liviu.dudau@arm.com> X-Mailer: git-send-email 2.13.2 In-Reply-To: <20170714151856.32041-1-liviu.dudau@arm.com> References: <20170714151856.32041-1-liviu.dudau@arm.com> Cc: Boris Brezillon , DRI devel X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" From: Brian Starkey Add tests for the WRITEBACK_PIXEL_FORMATS, WRITEBACK_OUT_FENCE_PTR and WRITEBACK_FB_ID properties on writeback connectors, ensuring their behaviour is correct. Signed-off-by: Brian Starkey --- lib/igt_kms.c | 6 +- lib/igt_kms.h | 7 + tests/Makefile.sources | 1 + tests/kms_writeback.c | 371 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 382 insertions(+), 3 deletions(-) create mode 100644 tests/kms_writeback.c diff --git a/lib/igt_kms.c b/lib/igt_kms.c index 02e2b274..aae32202 100644 --- a/lib/igt_kms.c +++ b/lib/igt_kms.c @@ -2137,7 +2137,7 @@ static uint32_t igt_plane_get_fb_gem_handle(igt_plane_t *plane) /* * Add position and fb changes of a plane to the atomic property set */ -static void +void igt_atomic_prepare_plane_commit(igt_plane_t *plane, igt_pipe_t *pipe, drmModeAtomicReq *req) { @@ -2515,7 +2515,7 @@ igt_pipe_replace_blob(igt_pipe_t *pipe, uint64_t *blob, void *ptr, size_t length /* * Add crtc property changes to the atomic property set */ -static void igt_atomic_prepare_crtc_commit(igt_pipe_t *pipe_obj, drmModeAtomicReq *req) +void igt_atomic_prepare_crtc_commit(igt_pipe_t *pipe_obj, drmModeAtomicReq *req) { if (pipe_obj->background_changed) igt_atomic_populate_crtc_req(req, pipe_obj, IGT_CRTC_BACKGROUND, pipe_obj->background); @@ -2567,7 +2567,7 @@ static void igt_atomic_prepare_crtc_commit(igt_pipe_t *pipe_obj, drmModeAtomicRe /* * Add connector property changes to the atomic property set */ -static void igt_atomic_prepare_connector_commit(igt_output_t *output, drmModeAtomicReq *req) +void igt_atomic_prepare_connector_commit(igt_output_t *output, drmModeAtomicReq *req) { struct kmstest_connector_config *config = &output->config; diff --git a/lib/igt_kms.h b/lib/igt_kms.h index ce9a35ef..ab8ec764 100644 --- a/lib/igt_kms.h +++ b/lib/igt_kms.h @@ -533,6 +533,8 @@ static inline bool igt_output_is_connected(igt_output_t *output) #define igt_atomic_populate_plane_req(req, plane, prop, value) \ igt_assert_lt(0, drmModeAtomicAddProperty(req, plane->drm_plane->plane_id,\ plane->atomic_props_plane[prop], value)) +void igt_atomic_prepare_plane_commit(igt_plane_t *plane, igt_pipe_t *pipe, + drmModeAtomicReq *req); /** * igt_atomic_populate_crtc_req: @@ -544,6 +546,9 @@ static inline bool igt_output_is_connected(igt_output_t *output) #define igt_atomic_populate_crtc_req(req, pipe, prop, value) \ igt_assert_lt(0, drmModeAtomicAddProperty(req, pipe->crtc_id,\ pipe->atomic_props_crtc[prop], value)) + +void igt_atomic_prepare_crtc_commit(igt_pipe_t *pipe_obj, drmModeAtomicReq *req); + /** * igt_atomic_populate_connector_req: * @req: A pointer to drmModeAtomicReq @@ -555,6 +560,8 @@ static inline bool igt_output_is_connected(igt_output_t *output) igt_assert_lt(0, drmModeAtomicAddProperty(req, output->config.connector->connector_id,\ output->config.atomic_props_connector[prop], value)) +void igt_atomic_prepare_connector_commit(igt_output_t *output, drmModeAtomicReq *req); + void igt_enable_connectors(void); void igt_reset_connectors(void); diff --git a/tests/Makefile.sources b/tests/Makefile.sources index 5b98a5a3..7318855d 100644 --- a/tests/Makefile.sources +++ b/tests/Makefile.sources @@ -213,6 +213,7 @@ TESTS_progs = \ kms_tv_load_detect \ kms_universal_plane \ kms_vblank \ + kms_writeback \ meta_test \ perf \ pm_backlight \ diff --git a/tests/kms_writeback.c b/tests/kms_writeback.c new file mode 100644 index 00000000..d2066482 --- /dev/null +++ b/tests/kms_writeback.c @@ -0,0 +1,371 @@ +/* + * (C) COPYRIGHT 2017 ARM Limited. All rights reserved. + * + * 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. + * + */ + +#include +#include +#include +#include + +#include "igt.h" +#include "igt_fb.h" + +/* We need to define these ourselves until we get an updated libdrm */ +#ifndef DRM_MODE_CONNECTOR_WRITEBACK +#define DRM_MODE_CONNECTOR_WRITEBACK 18 +#endif + +static drmModePropertyBlobRes *get_writeback_formats_blob(igt_output_t *output) +{ + drmModePropertyBlobRes *blob = NULL; + uint64_t blob_id; + int ret; + + ret = kmstest_get_property(output->display->drm_fd, + output->config.connector->connector_id, + DRM_MODE_OBJECT_CONNECTOR, + igt_connector_prop_names[IGT_CONNECTOR_WRITEBACK_PIXEL_FORMATS], + NULL, &blob_id, NULL); + if (ret) + blob = drmModeGetPropertyBlob(output->display->drm_fd, blob_id); + + igt_assert(blob); + + return blob; +} + +static uint32_t pick_writeback_format(igt_output_t *output) +{ + drmModePropertyBlobRes *wb_formats_blob = get_writeback_formats_blob(output); + const uint32_t *wb_formats, *cairo_formats; + uint32_t format = 0; + int n_cairo_formats, n_wb_formats, i, j; + + igt_get_all_cairo_formats(&cairo_formats, &n_cairo_formats); + + wb_formats = wb_formats_blob->data; + n_wb_formats = wb_formats_blob->length / sizeof(*wb_formats); + for (i = 0; (i < n_wb_formats) && !format; i++) { + for (j = 0; j < n_cairo_formats; j++) { + if (wb_formats[i] == cairo_formats[j]) { + format = wb_formats[i]; + break; + } + } + } + + drmModeFreePropertyBlob(wb_formats_blob); + + igt_assert(format); + return format; +} + +static bool check_writeback_config(igt_display_t *display, igt_output_t *output) +{ + igt_fb_t input_fb, output_fb; + igt_plane_t *plane; + uint32_t writeback_format = pick_writeback_format(output); + uint64_t tiling = igt_fb_mod_to_tiling(0); + int width, height, ret; + drmModeModeInfo override_mode = { + .clock = 25175, + .hdisplay = 640, + .hsync_start = 656, + .hsync_end = 752, + .htotal = 800, + .hskew = 0, + .vdisplay = 480, + .vsync_start = 490, + .vsync_end = 492, + .vtotal = 525, + .vscan = 0, + .vrefresh = 60, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, + .name = {"640x480-60"}, + }; + igt_output_override_mode(output, &override_mode); + + width = override_mode.hdisplay; + height = override_mode.vdisplay; + + ret = igt_create_fb(display->drm_fd, width, height, DRM_FORMAT_XRGB8888, + tiling, &input_fb); + igt_assert(ret >= 0); + + ret = igt_create_fb(display->drm_fd, width, height, writeback_format, + tiling, &output_fb); + igt_assert(ret >= 0); + + plane = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY); + igt_plane_set_fb(plane, &input_fb); + igt_output_set_writeback_fb(output, &output_fb); + + ret = igt_display_try_commit_atomic(display, DRM_MODE_ATOMIC_TEST_ONLY | + DRM_MODE_ATOMIC_ALLOW_MODESET, NULL); + igt_plane_set_fb(plane, NULL); + igt_remove_fb(display->drm_fd, &input_fb); + igt_remove_fb(display->drm_fd, &output_fb); + + return !ret; +} + +static igt_output_t *kms_writeback_get_output(igt_display_t *display) +{ + int i; + + for (i = 0; i < display->n_outputs; i++) { + igt_output_t *output = &display->outputs[i]; + int j; + + if (output->config.connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) + continue; + + kmstest_force_connector(display->drm_fd, output->config.connector, FORCE_CONNECTOR_ON); + + for (j = 0; j < igt_display_get_n_pipes(display); j++) { + igt_output_set_pipe(output, j); + + if (check_writeback_config(display, output)) { + igt_debug("Using connector %u:%s on pipe %d\n", + output->config.connector->connector_id, + output->name, j); + return output; + } + } + + /* Restore any connectors we don't use, so we don't trip on them later */ + kmstest_force_connector(display->drm_fd, output->config.connector, FORCE_CONNECTOR_UNSPECIFIED); + } + + return NULL; +} + +static void check_writeback_fb_id(igt_output_t *output) +{ + bool found; + uint64_t check_fb_id; + + found = kmstest_get_property(output->display->drm_fd, output->id, + DRM_MODE_OBJECT_CONNECTOR, + igt_connector_prop_names[IGT_CONNECTOR_WRITEBACK_FB_ID], + NULL, &check_fb_id, NULL); + igt_assert(found && (check_fb_id == 0)); +} + +static int do_writeback_test(igt_output_t *output, uint32_t flags, + uint32_t fb_id, int32_t *out_fence_ptr, + bool ptr_valid) +{ + int ret; + enum pipe pipe; + drmModeAtomicReq *req; + igt_display_t *display = output->display; + struct kmstest_connector_config *config = &output->config; + + req = drmModeAtomicAlloc(); + drmModeAtomicSetCursor(req, 0); + + for_each_pipe(display, pipe) { + igt_pipe_t *pipe_obj = &display->pipes[pipe]; + igt_plane_t *plane; + + /* + * Add CRTC Properties to the property set + */ + igt_atomic_prepare_crtc_commit(pipe_obj, req); + + for_each_plane_on_pipe(display, pipe, plane) { + igt_atomic_prepare_plane_commit(plane, pipe_obj, req); + } + } + + igt_atomic_populate_connector_req(req, output, IGT_CONNECTOR_CRTC_ID, config->crtc->crtc_id); + igt_atomic_populate_connector_req(req, output, IGT_CONNECTOR_WRITEBACK_FB_ID, fb_id); + igt_atomic_populate_connector_req(req, output, IGT_CONNECTOR_WRITEBACK_OUT_FENCE_PTR, (uint64_t)out_fence_ptr); + + if (ptr_valid) + *out_fence_ptr = 0; + + ret = drmModeAtomicCommit(display->drm_fd, req, flags, NULL); + + if (ptr_valid && (ret || (flags & DRM_MODE_ATOMIC_TEST_ONLY))) + igt_assert(*out_fence_ptr == -1); + + drmModeAtomicFree(req); + + /* WRITEBACK_FB_ID must always read as zero */ + check_writeback_fb_id(output); + + return ret; +} + +static void invalid_out_fence(igt_output_t *output, igt_fb_t *valid_fb, igt_fb_t *invalid_fb) +{ + int i, ret; + int32_t out_fence; + struct { + uint32_t fb_id; + bool ptr_valid; + int32_t *out_fence_ptr; + } invalid_tests[] = { + { + /* No output buffer, but the WRITEBACK_OUT_FENCE_PTR set. */ + .fb_id = 0, + .ptr_valid = true, + .out_fence_ptr = &out_fence, + }, + { + /* Invalid output buffer. */ + .fb_id = invalid_fb->fb_id, + .ptr_valid = true, + .out_fence_ptr = &out_fence, + }, + { + /* Invalid WRITEBACK_OUT_FENCE_PTR. */ + .fb_id = valid_fb->fb_id, + .ptr_valid = false, + .out_fence_ptr = (int32_t *)0x8, + }, + }; + + for (i = 0; i < ARRAY_SIZE(invalid_tests); i++) { + ret = do_writeback_test(output, DRM_MODE_ATOMIC_ALLOW_MODESET, + invalid_tests[i].fb_id, + invalid_tests[i].out_fence_ptr, + invalid_tests[i].ptr_valid); + igt_assert(ret != 0); + } +} + +static void writeback_fb_id(igt_output_t *output, igt_fb_t *valid_fb, igt_fb_t *invalid_fb) +{ + + int ret; + + /* Valid output buffer */ + ret = do_writeback_test(output, DRM_MODE_ATOMIC_ALLOW_MODESET, + valid_fb->fb_id, NULL, false); + igt_assert(ret == 0); + + /* Invalid object for WRITEBACK_FB_ID */ + ret = do_writeback_test(output, DRM_MODE_ATOMIC_ALLOW_MODESET, + output->id, NULL, false); + igt_assert(ret == -EINVAL); + + /* Zero WRITEBACK_FB_ID */ + ret = do_writeback_test(output, DRM_MODE_ATOMIC_ALLOW_MODESET, + 0, NULL, false); + igt_assert(ret == 0); +} + +igt_main +{ + igt_display_t display; + igt_output_t *output; + igt_plane_t *plane; + igt_fb_t input_fb; + drmModeModeInfo mode; + int ret; + + memset(&display, 0, sizeof(display)); + + igt_fixture { + display.drm_fd = drm_open_driver_master(DRIVER_ANY); + igt_assert_fd(display.drm_fd); + + kmstest_set_vt_graphics_mode(); + + igt_display_init(&display, display.drm_fd); + + igt_require(display.is_atomic); + + output = kms_writeback_get_output(&display); + igt_require(output); + + if (output->use_override_mode) + memcpy(&mode, &output->override_mode, sizeof(mode)); + else + memcpy(&mode, &output->config.default_mode, sizeof(mode)); + + plane = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY); + igt_require(plane); + + ret = igt_create_fb(display.drm_fd, mode.hdisplay, + mode.vdisplay, + DRM_FORMAT_XRGB8888, + igt_fb_mod_to_tiling(0), + &input_fb); + igt_assert(ret >= 0); + igt_plane_set_fb(plane, &input_fb); + } + + igt_subtest("writeback-pixel-formats") { + drmModePropertyBlobRes *formats_blob = get_writeback_formats_blob(output); + const char *valid_chars = "0123456 ABCGNRUXY"; + unsigned int i; + char *c; + + /* + * We don't have a comprehensive list of formats, so just check + * that the blob length is sensible and that it doesn't contain + * any outlandish characters + */ + igt_assert(!(formats_blob->length % 4)); + c = formats_blob->data; + for (i = 0; i < formats_blob->length; i++) + igt_assert_f(strchr(valid_chars, c[i]), + "Unexpected character %c\n", c[i]); + } + + igt_subtest("writeback-invalid-out-fence") { + igt_fb_t invalid_fb; + ret = igt_create_fb(display.drm_fd, mode.hdisplay / 2, + mode.vdisplay / 2, + DRM_FORMAT_XRGB8888, + igt_fb_mod_to_tiling(0), + &invalid_fb); + igt_require(ret > 0); + + invalid_out_fence(output, &input_fb, &invalid_fb); + + igt_remove_fb(display.drm_fd, &invalid_fb); + } + + igt_subtest("writeback-fb-id") { + igt_fb_t output_fb; + ret = igt_create_fb(display.drm_fd, mode.hdisplay, mode.vdisplay, + DRM_FORMAT_XRGB8888, + igt_fb_mod_to_tiling(0), + &output_fb); + igt_require(ret > 0); + + writeback_fb_id(output, &input_fb, &output_fb); + + igt_remove_fb(display.drm_fd, &output_fb); + } + + igt_fixture { + igt_remove_fb(display.drm_fd, &input_fb); + igt_display_fini(&display); + } +} From patchwork Fri Jul 14 15:18:53 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Liviu Dudau X-Patchwork-Id: 107812 Delivered-To: patch@linaro.org Received: by 10.182.45.195 with SMTP id p3csp1104592obm; Fri, 14 Jul 2017 08:20:15 -0700 (PDT) X-Received: by 10.99.174.14 with SMTP id q14mr4004202pgf.111.1500045615288; Fri, 14 Jul 2017 08:20:15 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1500045615; cv=none; d=google.com; s=arc-20160816; b=GfeD872t3Ulu7aJd8B0oAR/1i6/DZQgky7LlKBLYTwdAb3tQq/xBSYq87yBs6zPNik LfRCrkVjRjoJVQU7bpVfXXsmgzZHW+NizA+/tjieI4Pw237a2ufOIZ9I0UOEL2NR8Dmu JU7YTtdpBXK3v7PcCgpCn3vFFhqnqyr2SWmpDrf0/InIC9lxlgYrEXB8XvW6qOXF+4Sy wW8NAX1z5m4ofr/7H7MJX+den7QMBVexPyuifBjoM5P98c48GAJYKOtWix1cVoKC2r3e ULQast/onfyLqrdNP833+4kiFDD+jTvKuqYlNcTrQt9upLwfMCBs0jn4J4N8Mko4L322 3LYw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:cc:references:in-reply-to:message-id:date :subject:to:from:delivered-to:arc-authentication-results; bh=AWVv9CKeW43iwVETBqyzX+m500GfmFY2acZ2zYeVXpQ=; b=OFQjZx6UA0MC85OEBbzv7ct6RFpKhfgYZgGpFzGpSYf77drDlYBmzF/cxEzV0alsj8 wUyFQn1yXGolR0YCEjQPIHFddQw4YXM51/3sgqN1zf3xsm7Q74c+BidArtKL203D6Ffs EN00HKrQew/vEuK3wx25FuajlEdeG95Xpk7kaEq23hqZjaNOB1P8z/92Cc9nWW4L+C0p UYdPW/Z+UISi4P5jHVqdgtbVDd/3KkbABZzVzaNuO72gBm3EqLpJ/t5nDxNGskdC/5oc iCIvUt//8GqoZIp7q4gwCdzgc/R8BdIn+CeIDTIApK7Rv7ded5SQK3+SiC05XiSzpD9R e5Ww== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of dri-devel-bounces@lists.freedesktop.org designates 131.252.210.177 as permitted sender) smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Return-Path: Received: from gabe.freedesktop.org (gabe.freedesktop.org. [131.252.210.177]) by mx.google.com with ESMTPS id q18si6840856pgd.436.2017.07.14.08.20.13 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 14 Jul 2017 08:20:15 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of dri-devel-bounces@lists.freedesktop.org designates 131.252.210.177 as permitted sender) client-ip=131.252.210.177; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of dri-devel-bounces@lists.freedesktop.org designates 131.252.210.177 as permitted sender) smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 7FB036E87B; Fri, 14 Jul 2017 15:19:09 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from cam-smtp0.cambridge.arm.com (fw-tnat.cambridge.arm.com [217.140.96.140]) by gabe.freedesktop.org (Postfix) with ESMTPS id 9C8B36E862; Fri, 14 Jul 2017 15:19:01 +0000 (UTC) Received: from e110455-lin.cambridge.arm.com (e110455-lin.cambridge.arm.com [10.2.131.9]) by cam-smtp0.cambridge.arm.com (8.13.8/8.13.8) with ESMTP id v6EFIuFN000867; Fri, 14 Jul 2017 16:18:57 +0100 From: Liviu Dudau To: Intel GFX discussion Subject: [PATCH i-g-t v2 4/7] lib: Add function to hash a framebuffer Date: Fri, 14 Jul 2017 16:18:53 +0100 Message-Id: <20170714151856.32041-5-liviu.dudau@arm.com> X-Mailer: git-send-email 2.13.2 In-Reply-To: <20170714151856.32041-1-liviu.dudau@arm.com> References: <20170714151856.32041-1-liviu.dudau@arm.com> Cc: Boris Brezillon , DRI devel X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" From: Brian Starkey To use writeback buffers as a CRC source, we need to be able to hash them. Implement a simple FVA-1a hashing routine for this purpose. Doing a bytewise hash on the framebuffer directly can be very slow if the memory is noncached. By making a copy of each line in the FB first (which can take advantage of word-access speedup), we can do the hash on a cached copy, which is much faster (10x speedup on my platform). Signed-off-by: Brian Starkey --- lib/igt_fb.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/igt_fb.h | 5 +++++ 2 files changed, 70 insertions(+) diff --git a/lib/igt_fb.c b/lib/igt_fb.c index d2b7e9e3..f613bb2e 100644 --- a/lib/igt_fb.c +++ b/lib/igt_fb.c @@ -1302,3 +1302,68 @@ void igt_get_all_cairo_formats(const uint32_t **formats, int *format_count) *formats = drm_formats; *format_count = n_formats; } + +/* + * This implements the FNV-1a hashing algorithm instead of CRC, for + * simplicity + * http://www.isthe.com/chongo/tech/comp/fnv/index.html + * + * hash = offset_basis + * for each octet_of_data to be hashed + * hash = hash xor octet_of_data + * hash = hash * FNV_prime + * return hash + * + * 32 bit offset_basis = 2166136261 + * 32 bit FNV_prime = 224 + 28 + 0x93 = 16777619 + */ +int igt_fb_get_crc(struct igt_fb *fb, igt_crc_t *crc) +{ +#define FNV1a_OFFSET_BIAS 2166136261 +#define FNV1a_PRIME 16777619 + uint32_t hash; + void *map; + char *ptr, *line = NULL; + int x, y, cpp = igt_drm_format_to_bpp(fb->drm_format) / 8; + + if (fb->is_dumb) + map = kmstest_dumb_map_buffer(fb->fd, fb->gem_handle, fb->size, + PROT_READ); + else + map = gem_mmap__gtt(fb->fd, fb->gem_handle, fb->size, + PROT_READ); + ptr = map; + + /* + * Framebuffers are often uncached, which can make byte-wise accesses + * very slow. We copy each line of the FB into a local buffer to speed + * up the hashing. + */ + line = malloc(fb->stride); + if (!line) { + munmap(map, fb->size); + return -ENOMEM; + } + + hash = FNV1a_OFFSET_BIAS; + + for (y = 0; y < fb->height; y++, ptr += fb->stride) { + + memcpy(line, ptr, fb->stride); + + for (x = 0; x < fb->width * cpp; x++) { + hash ^= line[x]; + hash *= FNV1a_PRIME; + } + } + + crc->n_words = 1; + crc->crc[0] = hash; + + free(line); + munmap(map, fb->size); + + return 0; +#undef FNV1a_OFFSET_BIAS +#undef FNV1a_PRIME +} diff --git a/lib/igt_fb.h b/lib/igt_fb.h index 4a680cef..04430e9d 100644 --- a/lib/igt_fb.h +++ b/lib/igt_fb.h @@ -43,6 +43,8 @@ typedef struct _cairo cairo_t; #include +#include "igt_crc.h" + /** * igt_fb_t: * @fb_id: KMS ID of the framebuffer @@ -156,5 +158,8 @@ uint32_t igt_drm_format_to_bpp(uint32_t drm_format); const char *igt_format_str(uint32_t drm_format); void igt_get_all_cairo_formats(const uint32_t **formats, int *format_count); +/* Get a hash for a framebuffer */ +int igt_fb_get_crc(struct igt_fb *fb, igt_crc_t *crc); + #endif /* __IGT_FB_H__ */ From patchwork Fri Jul 14 15:18:54 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Liviu Dudau X-Patchwork-Id: 107806 Delivered-To: patch@linaro.org Received: by 10.140.101.44 with SMTP id t41csp1034194qge; Fri, 14 Jul 2017 08:19:11 -0700 (PDT) X-Received: by 10.98.54.196 with SMTP id d187mr5910665pfa.169.1500045551482; Fri, 14 Jul 2017 08:19:11 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1500045551; cv=none; d=google.com; s=arc-20160816; b=zaZ51UJ5YuGP/uQsuMlygaCqy8De0hm3np6u6vDaNtuozbg/CN/LQxY2KQr0atWiat j5nhPFwKCW99TZOVSFJZLylvhzCj3TEywZzA6Y8cWo7VCjpvuUXLqva0dMvfQVtjyg4X sF1i8tEXB3BB+Z7p7nij2q9KvJ1O9qKyAy26to7Qern1Frq1+wRjVY1/KxTC1NikpmRE WQE7jpfhX6T/SiG+8y6CPqoIHJ2eIH7LPeau8c6et2XOq4fRlyXIOab7c8Af/9u1hjFU IiJv8QJ964t8YLN3B7BMKtcsPmugskUDCQoswzNFSdqAul/tnyCTMlWl1M3PC7IbhylU ofuw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:cc:references:in-reply-to:message-id:date :subject:to:from:delivered-to:arc-authentication-results; bh=k/kNDg+jTgmCoNySEp4KoXfq0xQVifCD3b526Ct/mUQ=; b=Aqs0O7lFrshyUYlemNY3MdHUKTseVKvhFSWU5rIMhSsCbmJA5uBiQE6AkNpB1a28oN E5xldWXC6E2UM/uJ4THilHcqcmmX3s7TFCi8OORELD3uYnfzfq4eTMoxqpZ5QsI1Necc EBiuEUAD5rxEThENsgZROczUzeX+XypQ3JL0YjNdG1s+xlJKTC8/dAxAp/s8VWA9sLMG KJGXDfbLqrc2AgD0o2m88T5yg5mdQavLEIFEmTsn+Mgy1Af/fUCNcHN1+etsqm5Ejgxm lcrWFQ+sSEygWkXmt/fWgu+Zl5hBwzhDUpSYVGX2ZQ+TPF64LQtFzGpto0uJWvxoWbOs yvmw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of dri-devel-bounces@lists.freedesktop.org designates 131.252.210.177 as permitted sender) smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Return-Path: Received: from gabe.freedesktop.org (gabe.freedesktop.org. [131.252.210.177]) by mx.google.com with ESMTPS id v19si6542941pgc.246.2017.07.14.08.19.11 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 14 Jul 2017 08:19:11 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of dri-devel-bounces@lists.freedesktop.org designates 131.252.210.177 as permitted sender) client-ip=131.252.210.177; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of dri-devel-bounces@lists.freedesktop.org designates 131.252.210.177 as permitted sender) smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 59BE66E862; Fri, 14 Jul 2017 15:19:04 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from cam-smtp0.cambridge.arm.com (fw-tnat.cambridge.arm.com [217.140.96.140]) by gabe.freedesktop.org (Postfix) with ESMTPS id D8BD36E870; Fri, 14 Jul 2017 15:19:01 +0000 (UTC) Received: from e110455-lin.cambridge.arm.com (e110455-lin.cambridge.arm.com [10.2.131.9]) by cam-smtp0.cambridge.arm.com (8.13.8/8.13.8) with ESMTP id v6EFIuFO000867; Fri, 14 Jul 2017 16:18:57 +0100 From: Liviu Dudau To: Intel GFX discussion Subject: [PATCH i-g-t v2 5/7] kms_writeback: Add writeback-check-output Date: Fri, 14 Jul 2017 16:18:54 +0100 Message-Id: <20170714151856.32041-6-liviu.dudau@arm.com> X-Mailer: git-send-email 2.13.2 In-Reply-To: <20170714151856.32041-1-liviu.dudau@arm.com> References: <20170714151856.32041-1-liviu.dudau@arm.com> Cc: Boris Brezillon , DRI devel X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" From: Brian Starkey Add a test which makes commits using the writeback connector, and checks the output buffer hash to make sure it is/isn't written as appropriate. Signed-off-by: Brian Starkey --- tests/kms_writeback.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/tests/kms_writeback.c b/tests/kms_writeback.c index d2066482..8201a81c 100644 --- a/tests/kms_writeback.c +++ b/tests/kms_writeback.c @@ -29,6 +29,7 @@ #include "igt.h" #include "igt_fb.h" +#include "sw_sync.h" /* We need to define these ourselves until we get an updated libdrm */ #ifndef DRM_MODE_CONNECTOR_WRITEBACK @@ -278,6 +279,115 @@ static void writeback_fb_id(igt_output_t *output, igt_fb_t *valid_fb, igt_fb_t * igt_assert(ret == 0); } +static void fill_fb(igt_fb_t *fb, double color[3]) +{ + cairo_t *cr = igt_get_cairo_ctx(fb->fd, fb); + igt_assert(cr); + + igt_paint_color(cr, 0, 0, fb->width, fb->height, + color[0], color[1], color[2]); +} + +static void get_and_wait_out_fence(igt_output_t *output) +{ + int ret, out_fence = out_fence = igt_output_get_last_writeback_out_fence(output); + igt_assert(out_fence >= 0); + + ret = sync_fence_wait(out_fence, 1000); + igt_assert(ret == 0); + close(out_fence); +} + +static void writeback_seqence(igt_output_t *output, igt_plane_t *plane, + igt_fb_t *in_fb, igt_fb_t *out_fbs[], int n_commits) +{ + int i, color_idx = 0; + double in_fb_colors[2][3] = { + { 1.0, 0.0, 0.0 }, + { 0.0, 1.0, 0.0 }, + }; + double clear_color[3] = { 1.0, 1.0, 1.0 }; + igt_crc_t cleared_crc, out_expected; + + for (i = 0; i < n_commits; i++, color_idx++) { + /* Change the input color each time */ + fill_fb(in_fb, in_fb_colors[color_idx % 2]); + + if (out_fbs[i]) { + igt_crc_t out_before; + + /* Get the expected CRC */ + fill_fb(out_fbs[i], in_fb_colors[color_idx % 2]); + igt_fb_get_crc(out_fbs[i], &out_expected); + + fill_fb(out_fbs[i], clear_color); + if (i == 0) + igt_fb_get_crc(out_fbs[i], &cleared_crc); + igt_fb_get_crc(out_fbs[i], &out_before); + igt_assert_crc_equal(&cleared_crc, &out_before); + } + + /* Commit */ + igt_plane_set_fb(plane, in_fb); + igt_output_set_writeback_fb(output, out_fbs[i]); + if (out_fbs[i]) + igt_output_request_writeback_out_fence(output); + igt_display_commit_atomic(output->display, + DRM_MODE_ATOMIC_ALLOW_MODESET, + NULL); + if (out_fbs[i]) + get_and_wait_out_fence(output); + + /* Make sure the old output buffer is untouched */ + if (i > 0 && out_fbs[i - 1] && (out_fbs[i] != out_fbs[i - 1])) { + igt_crc_t out_prev; + igt_fb_get_crc(out_fbs[i - 1], &out_prev); + igt_assert_crc_equal(&cleared_crc, &out_prev); + } + + /* Make sure this output buffer is written */ + if (out_fbs[i]) { + igt_crc_t out_after; + igt_fb_get_crc(out_fbs[i], &out_after); + igt_assert_crc_equal(&out_expected, &out_after); + + /* And clear it, for the next time */ + fill_fb(out_fbs[i], clear_color); + } + } +} + +static void writeback_check_output(igt_output_t *output, igt_plane_t *plane, + igt_fb_t *input_fb, igt_fb_t *output_fb) +{ + igt_fb_t *out_fbs[2] = { 0 }; + igt_fb_t second_out_fb; + int ret; + + /* One commit, with a writeback. */ + writeback_seqence(output, plane, input_fb, &output_fb, 1); + + /* Two commits, the second with no writeback */ + out_fbs[0] = output_fb; + writeback_seqence(output, plane, input_fb, out_fbs, 2); + + /* Two commits, both with writeback */ + out_fbs[1] = output_fb; + writeback_seqence(output, plane, input_fb, out_fbs, 2); + + ret = igt_create_fb(output_fb->fd, output_fb->width, output_fb->height, + DRM_FORMAT_XRGB8888, + igt_fb_mod_to_tiling(0), + &second_out_fb); + igt_require(ret > 0); + + /* Two commits, with different writeback buffers */ + out_fbs[1] = &second_out_fb; + writeback_seqence(output, plane, input_fb, out_fbs, 2); + + igt_remove_fb(output_fb->fd, &second_out_fb); +} + igt_main { igt_display_t display; @@ -364,6 +474,19 @@ igt_main igt_remove_fb(display.drm_fd, &output_fb); } + igt_subtest("writeback-check-output") { + igt_fb_t output_fb; + ret = igt_create_fb(display.drm_fd, mode.hdisplay, mode.vdisplay, + DRM_FORMAT_XRGB8888, + igt_fb_mod_to_tiling(0), + &output_fb); + igt_require(ret > 0); + + writeback_check_output(output, plane, &input_fb, &output_fb); + + igt_remove_fb(display.drm_fd, &output_fb); + } + igt_fixture { igt_remove_fb(display.drm_fd, &input_fb); igt_display_fini(&display); From patchwork Fri Jul 14 15:18:55 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Liviu Dudau X-Patchwork-Id: 107805 Delivered-To: patch@linaro.org Received: by 10.140.101.44 with SMTP id t41csp1034101qge; Fri, 14 Jul 2017 08:19:06 -0700 (PDT) X-Received: by 10.99.101.132 with SMTP id z126mr15257680pgb.64.1500045546402; Fri, 14 Jul 2017 08:19:06 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1500045546; cv=none; d=google.com; s=arc-20160816; b=LxEr4t5SJmOSGugNUKsrVCTslQvoKVVqHDQ5OSRBJI9oNk1zUnLUpmlVAKH1PYm1oP 5dKU01WCIdlXLHGtrRixQvvQ/gtTHfOPdfz9xy7GnZJEAIIQ1dOmRzBGEZazNkOfq9zw DznZRub+XUl2/McjkSBYodKUi9zXI4b6VXjYDubLgzsg9mbH8NklBWx1JGIIhtm6bMjC mqDejISs+VLDv3roiNuz20bB/iYR9HdgqXOZdz02+Oo7BGkjlL2v6vlru3P39ZkHTk1f +kB7fLMSsuUqkUNPemE7x80EzTXWfspXDbtEZaFT1yY2vNBUCq4wnySyt0Pi+CUvL+X2 8uxQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:cc:references:in-reply-to:message-id:date :subject:to:from:delivered-to:arc-authentication-results; bh=HI/sGwRl5nQFSJN6lpVTpX7C05irz3v4ysysSwmmTSo=; b=jLhkFpOVEot+GwXeiXOsOM5HZobtx22W/FxfVc5QVK+6aZZJawbapjJb+u76IFMd/Q 8yVt2i5KWvxJhbt/qOhkclUvY/xX/jtGLgZqZAxkVLaO0YW1vyyX+A/OhVyyeXAbO8re qGfQn902YUnhootRDPL1wA+feXu7qSHTO3SmN1g91K1apWrlWrQh5c5c4XOG3NV98yuI X5SrF4vOaO8Gah7Hit6C5CRLcajJwhPj5vSaaHfxhVIDdpfwBF6auTbNmGmbln8pDFsj oaun/+2VSoIbNtD3V8sZBxYiHRHiAbZ4rlqvrNhEfHVVyshzUhrc1I2JRxJIgMP9aPyU S3Rg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of dri-devel-bounces@lists.freedesktop.org designates 131.252.210.177 as permitted sender) smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Return-Path: Received: from gabe.freedesktop.org (gabe.freedesktop.org. [131.252.210.177]) by mx.google.com with ESMTPS id o21si369831pgj.262.2017.07.14.08.19.06 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 14 Jul 2017 08:19:06 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of dri-devel-bounces@lists.freedesktop.org designates 131.252.210.177 as permitted sender) client-ip=131.252.210.177; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of dri-devel-bounces@lists.freedesktop.org designates 131.252.210.177 as permitted sender) smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 01CE66E869; Fri, 14 Jul 2017 15:19:03 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from cam-smtp0.cambridge.arm.com (fw-tnat.cambridge.arm.com [217.140.96.140]) by gabe.freedesktop.org (Postfix) with ESMTPS id AD91E6E86D; Fri, 14 Jul 2017 15:19:01 +0000 (UTC) Received: from e110455-lin.cambridge.arm.com (e110455-lin.cambridge.arm.com [10.2.131.9]) by cam-smtp0.cambridge.arm.com (8.13.8/8.13.8) with ESMTP id v6EFIuFP000867; Fri, 14 Jul 2017 16:18:57 +0100 From: Liviu Dudau To: Intel GFX discussion Subject: [PATCH i-g-t v2 6/7] lib/igt_kms: Add igt_output_clone_pipe for cloning Date: Fri, 14 Jul 2017 16:18:55 +0100 Message-Id: <20170714151856.32041-7-liviu.dudau@arm.com> X-Mailer: git-send-email 2.13.2 In-Reply-To: <20170714151856.32041-1-liviu.dudau@arm.com> References: <20170714151856.32041-1-liviu.dudau@arm.com> Cc: Boris Brezillon , DRI devel X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" From: Brian Starkey An output can be added as a clone of any other output(s) attached to a pipe using igt_output_clone_pipe() Signed-off-by: Brian Starkey --- lib/igt_kms.c | 90 +++++++++++++++++++++++++++++++++++++---------------------- lib/igt_kms.h | 3 ++ 2 files changed, 59 insertions(+), 34 deletions(-) diff --git a/lib/igt_kms.c b/lib/igt_kms.c index aae32202..85dc0aa8 100644 --- a/lib/igt_kms.c +++ b/lib/igt_kms.c @@ -1560,6 +1560,17 @@ static void igt_display_log_shift(igt_display_t *display, int shift) igt_assert(display->log_shift >= 0); } +static int igt_output_idx(igt_output_t *output) +{ + int i; + + for (i = 0; i < output->display->n_outputs; i++) + if (&output->display->outputs[i] == output) + return i; + + return -1; +} + static void igt_output_refresh(igt_output_t *output) { igt_display_t *display = output->display; @@ -1990,40 +2001,6 @@ void igt_display_fini(igt_display_t *display) display->pipes = NULL; } -static void igt_display_refresh(igt_display_t *display) -{ - igt_output_t *output; - int i; - - unsigned long pipes_in_use = 0; - - /* Check that two outputs aren't trying to use the same pipe */ - for (i = 0; i < display->n_outputs; i++) { - output = &display->outputs[i]; - - if (pipes_in_use & output->pending_crtc_idx_mask) - goto report_dup; - - pipes_in_use |= output->pending_crtc_idx_mask; - - if (output->force_reprobe) - igt_output_refresh(output); - } - - return; - -report_dup: - for (; i > 0; i--) { - igt_output_t *b = &display->outputs[i - 1]; - - igt_assert_f(output->pending_crtc_idx_mask != - b->pending_crtc_idx_mask, - "%s and %s are both trying to use pipe %s\n", - igt_output_name(output), igt_output_name(b), - kmstest_pipe_name(ffs(b->pending_crtc_idx_mask) - 1)); - } -} - static igt_pipe_t *igt_output_get_driving_pipe(igt_output_t *output) { igt_display_t *display = output->display; @@ -2047,6 +2024,38 @@ static igt_pipe_t *igt_output_get_driving_pipe(igt_output_t *output) return &display->pipes[pipe]; } +static void igt_display_refresh(igt_display_t *display) +{ + igt_output_t *output; + igt_pipe_t *pipe; + int i; + + unsigned long pipes_in_use = 0; + + /* Check that outputs and pipes agree wrt. cloning */ + for (i = 0; i < display->n_outputs; i++) { + output = &display->outputs[i]; + + pipe = igt_output_get_driving_pipe(output); + if (pipe) { + igt_assert_f(pipe->outputs & (1 << igt_output_idx(output)), + "Output %s not expected to be using pipe %s\n", + igt_output_name(output), + kmstest_pipe_name(pipe->pipe)); + + if (pipes_in_use & output->pending_crtc_idx_mask) + LOG(display, "Output %s clones pipe %s\n", + igt_output_name(output), + kmstest_pipe_name(pipe->pipe)); + } + + pipes_in_use |= output->pending_crtc_idx_mask; + + if (output->force_reprobe) + igt_output_refresh(output); + } +} + static igt_plane_t *igt_pipe_get_plane(igt_pipe_t *pipe, int plane_idx) { igt_assert_f(plane_idx >= 0 && plane_idx < pipe->n_planes, @@ -2941,6 +2950,16 @@ void igt_output_override_mode(igt_output_t *output, drmModeModeInfo *mode) pipe->mode_changed = true; } +void igt_output_clone_pipe(igt_output_t *output, enum pipe pipe) +{ + igt_display_t *display = output->display; + uint32_t current_clones = display->pipes[pipe].outputs; + + igt_output_set_pipe(output, pipe); + + display->pipes[pipe].outputs |= current_clones; +} + void igt_output_set_pipe(igt_output_t *output, enum pipe pipe) { igt_display_t *display = output->display; @@ -2952,6 +2971,7 @@ void igt_output_set_pipe(igt_output_t *output, enum pipe pipe) old_pipe = igt_output_get_driving_pipe(output); old_pipe->mode_changed = true; + old_pipe->outputs &= ~(1 << igt_output_idx(output)); } if (pipe == PIPE_NONE) { @@ -2963,6 +2983,8 @@ void igt_output_set_pipe(igt_output_t *output, enum pipe pipe) output->pending_crtc_idx_mask = 1 << pipe; display->pipes[pipe].mode_changed = true; + + display->pipes[pipe].outputs = (1 << igt_output_idx(output)); } output->config.pipe_changed = true; diff --git a/lib/igt_kms.h b/lib/igt_kms.h index ab8ec764..9ddcfade 100644 --- a/lib/igt_kms.h +++ b/lib/igt_kms.h @@ -358,6 +358,8 @@ struct igt_pipe { int32_t out_fence_fd; bool out_fence_requested; + + uint32_t outputs; }; typedef struct { @@ -402,6 +404,7 @@ const char *igt_output_name(igt_output_t *output); drmModeModeInfo *igt_output_get_mode(igt_output_t *output); void igt_output_override_mode(igt_output_t *output, drmModeModeInfo *mode); void igt_output_set_pipe(igt_output_t *output, enum pipe pipe); +void igt_output_clone_pipe(igt_output_t *output, enum pipe pipe); void igt_output_set_scaling_mode(igt_output_t *output, uint64_t scaling_mode); igt_plane_t *igt_output_get_plane(igt_output_t *output, int plane_idx); From patchwork Fri Jul 14 15:18:56 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Liviu Dudau X-Patchwork-Id: 107810 Delivered-To: patch@linaro.org Received: by 10.140.101.44 with SMTP id t41csp1034994qge; Fri, 14 Jul 2017 08:19:53 -0700 (PDT) X-Received: by 10.98.163.203 with SMTP id q72mr5735316pfl.97.1500045593630; Fri, 14 Jul 2017 08:19:53 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1500045593; cv=none; d=google.com; s=arc-20160816; b=V/SDGL9UmImstAsBnDHMgDymzLG9Lhyod7wLwKZSJLCyctWxcimySAjsIAYu9Lwxti aC47xOqB3we9GSjKCIFD5DiT3gwFgMsmrIZHUmSzV5r1p1wUEtOF2EAXPR6BscL+6/34 io+aJOZTzHXbEhKR3TUC1bxWpYYrpckjSUslz+tCp2ZMhcYAoKu+XfcMVnpUugwhollS hU8RcesoNFedvlI/E+makxC3Yphdni2IUMYSgiu1SUJTzoAkJH6FoicVIJcV2mKZGS+o zYyIkhVFGg83WSNII3gm1rxeum3CmlblrU0D3xryoMvO45zlprToiaanDRmI1fU+xxXU bs4Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:cc:references:in-reply-to:message-id:date :subject:to:from:delivered-to:arc-authentication-results; bh=9MEeHweagjgnQiY2XY+EeqUS8DZImB1SQd69tR8CN54=; b=aljyL7dw7Igw4IYNzBTRVhIcF5Rigb/KTbTbxY3QtXwL/AeP4lHQ+vWiGMTfB3cFKo 668Mr8MH0k7Lu1vJg0cQ6aDOBMQpeBPEEOp557ZUizI64LM8IxXIQjUxH7vOqEqVt6Z9 L+de2nzEIwsxQ4WWTo/+4wzl54sBOd2nURuEbwWYWtS2peSE7n+lzm58UoMX/Sv16Igx mv5R6lAo5CIYqheC2MHm5ZPw0YhWUB0HaV/LtNI1z31bvr79TQeTjM9LWsqniQSeqon2 k3Bj4Z5/5WIbXTcEIpUAQMqAK95uKnI9I1LRbguXiWKkT4CecmAneV8iE2WujnFEiBLw TTyQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of dri-devel-bounces@lists.freedesktop.org designates 131.252.210.177 as permitted sender) smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Return-Path: Received: from gabe.freedesktop.org (gabe.freedesktop.org. [131.252.210.177]) by mx.google.com with ESMTPS id 36si7298077pla.124.2017.07.14.08.19.53 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 14 Jul 2017 08:19:53 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of dri-devel-bounces@lists.freedesktop.org designates 131.252.210.177 as permitted sender) client-ip=131.252.210.177; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of dri-devel-bounces@lists.freedesktop.org designates 131.252.210.177 as permitted sender) smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 6320C6E898; Fri, 14 Jul 2017 15:19:14 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from cam-smtp0.cambridge.arm.com (fw-tnat.cambridge.arm.com [217.140.96.140]) by gabe.freedesktop.org (Postfix) with ESMTPS id B826A6E86E; Fri, 14 Jul 2017 15:19:01 +0000 (UTC) Received: from e110455-lin.cambridge.arm.com (e110455-lin.cambridge.arm.com [10.2.131.9]) by cam-smtp0.cambridge.arm.com (8.13.8/8.13.8) with ESMTP id v6EFIuFQ000867; Fri, 14 Jul 2017 16:18:57 +0100 From: Liviu Dudau To: Intel GFX discussion Subject: [PATCH i-g-t v2 7/7] kms_writeback: Add tests using a cloned output Date: Fri, 14 Jul 2017 16:18:56 +0100 Message-Id: <20170714151856.32041-8-liviu.dudau@arm.com> X-Mailer: git-send-email 2.13.2 In-Reply-To: <20170714151856.32041-1-liviu.dudau@arm.com> References: <20170714151856.32041-1-liviu.dudau@arm.com> Cc: Boris Brezillon , DRI devel X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" From: Brian Starkey Update the connector search to also optionally attempt to find a non-writeback connector to clone to. Add a subtest which is the same as writeback-check-output, but also clones to the second connector. Signed-off-by: Brian Starkey --- tests/kms_writeback.c | 63 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 8 deletions(-) diff --git a/tests/kms_writeback.c b/tests/kms_writeback.c index 8201a81c..9a34bca0 100644 --- a/tests/kms_writeback.c +++ b/tests/kms_writeback.c @@ -81,7 +81,8 @@ static uint32_t pick_writeback_format(igt_output_t *output) return format; } -static bool check_writeback_config(igt_display_t *display, igt_output_t *output) +static bool check_writeback_config(igt_display_t *display, igt_output_t *output, + int pipe, igt_output_t **clone) { igt_fb_t input_fb, output_fb; igt_plane_t *plane; @@ -123,6 +124,27 @@ static bool check_writeback_config(igt_display_t *display, igt_output_t *output) ret = igt_display_try_commit_atomic(display, DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET, NULL); + if (!ret && clone) { + /* Try and find a clone */ + int i, newret; + *clone = NULL; + + for (i = 0; i < display->n_outputs; i++) { + igt_output_t *second_output = &display->outputs[i]; + if (output != second_output && + igt_pipe_connector_valid(pipe, second_output)) { + + igt_output_clone_pipe(second_output, pipe); + newret = igt_display_try_commit_atomic(display, DRM_MODE_ATOMIC_TEST_ONLY | + DRM_MODE_ATOMIC_ALLOW_MODESET, NULL); + igt_output_set_pipe(second_output, PIPE_NONE); + if (!newret) { + *clone = second_output; + break; + } + } + } + } igt_plane_set_fb(plane, NULL); igt_remove_fb(display->drm_fd, &input_fb); igt_remove_fb(display->drm_fd, &output_fb); @@ -130,7 +152,8 @@ static bool check_writeback_config(igt_display_t *display, igt_output_t *output) return !ret; } -static igt_output_t *kms_writeback_get_output(igt_display_t *display) +static igt_output_t *kms_writeback_get_output(igt_display_t *display, enum pipe *pipe, + igt_output_t **clone) { int i; @@ -146,10 +169,16 @@ static igt_output_t *kms_writeback_get_output(igt_display_t *display) for (j = 0; j < igt_display_get_n_pipes(display); j++) { igt_output_set_pipe(output, j); - if (check_writeback_config(display, output)) { + if (check_writeback_config(display, output, j, clone)) { igt_debug("Using connector %u:%s on pipe %d\n", output->config.connector->connector_id, output->name, j); + if (clone && *clone) + igt_debug("Cloning to connector %u:%s\n", + (*clone)->config.connector->connector_id, + (*clone)->name); + if (pipe) + *pipe = j; return output; } } @@ -190,9 +219,6 @@ static int do_writeback_test(igt_output_t *output, uint32_t flags, igt_pipe_t *pipe_obj = &display->pipes[pipe]; igt_plane_t *plane; - /* - * Add CRTC Properties to the property set - */ igt_atomic_prepare_crtc_commit(pipe_obj, req); for_each_plane_on_pipe(display, pipe, plane) { @@ -391,10 +417,11 @@ static void writeback_check_output(igt_output_t *output, igt_plane_t *plane, igt_main { igt_display_t display; - igt_output_t *output; + igt_output_t *output, *clone; igt_plane_t *plane; igt_fb_t input_fb; drmModeModeInfo mode; + enum pipe pipe; int ret; memset(&display, 0, sizeof(display)); @@ -409,7 +436,7 @@ igt_main igt_require(display.is_atomic); - output = kms_writeback_get_output(&display); + output = kms_writeback_get_output(&display, &pipe, &clone); igt_require(output); if (output->use_override_mode) @@ -487,6 +514,26 @@ igt_main igt_remove_fb(display.drm_fd, &output_fb); } + igt_subtest("writeback-check-output-clone") { + igt_fb_t output_fb; + + igt_require(clone); + + ret = igt_create_fb(display.drm_fd, mode.hdisplay, mode.vdisplay, + DRM_FORMAT_XRGB8888, + igt_fb_mod_to_tiling(0), + &output_fb); + igt_require(ret > 0); + + igt_output_clone_pipe(clone, pipe); + + writeback_check_output(output, plane, &input_fb, &output_fb); + + igt_output_set_pipe(clone, PIPE_NONE); + + igt_remove_fb(display.drm_fd, &output_fb); + } + igt_fixture { igt_remove_fb(display.drm_fd, &input_fb); igt_display_fini(&display);