[PATCH i-g-t] lib/igt_kms: Add COMIT_ATOMIC to igt_display_commit2()

Marius Vlad
2016-01-15T09:05:11Z

So far, we had only COMMIT_UNIVERSAL and COMMIT_LEGACY, using
drmModeSetPlane()/drmSetCrtc(). This patch adds COMMIT_ATOMIC
to igt_display_commit2() that makes use of drmModeAtomicCommit().

Signed-off-by: Marius Vlad <marius.c.vlad@intel.com>
---
lib/igt_kms.c | 190 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
lib/igt_kms.h | 33 +++++++++-
2 files changed, 221 insertions(+), 2 deletions(-)

diff --git a/lib/igt_kms.c b/lib/igt_kms.c
index 497118a..61f7a39 100644
--- a/lib/igt_kms.c
+++ b/lib/igt_kms.c
@@ -1306,6 +1306,191 @@ static uint32_t igt_plane_get_fb_gem_handle(igt_plane_t *plane)
igt_assert(r == 0); \
}

+static const char *igt_plane_prop_names[IGT_NUM_PLANE_PROPS] = {
+ "SRC_X",
+ "SRC_Y",
+ "SRC_W",
+ "SRC_H",
+ "CRTC_X",
+ "CRTC_Y",
+ "CRTC_W",
+ "CRTC_H",
+ "FB_ID",
+ "CRTC_ID",
+ "type"
+};
+
+/*
+ * Retrieve all the properies specified in props_name and store them into
+ * plane->atomic_props_plane.
+ */
+static void
+igt_atomic_fill_plane_props(igt_display_t *display, igt_plane_t *plane,
+ int type, int num_props, const char **prop_names)
+{
+ drmModeObjectPropertiesPtr props;
+ int i, j, fd;
+
+ fd = display->drm_fd;
+
+ props = drmModeObjectGetProperties(fd, plane->drm_plane->plane_id, type);
+ igt_assert(props);
+
+ for (i = 0; i < props->count_props; i++) {
+ drmModePropertyPtr prop =
+ drmModeGetProperty(fd, props->props[i]);
+
+ for (j = 0; j < num_props; j++) {
+ if (strcmp(prop->name, prop_names[j]) != 0)
+ continue;
+ plane->atomic_props_plane[j] = props->props[i];
+ break;
+ }
+
+ drmModeFreeProperty(prop);
+ }
+
+ drmModeFreeObjectProperties(props);
+}
+
+/*
+ * Commit position and fb changes to a DRM plane via the AtomicCommit()
+ * ioctl; if the DRM call to program the plane fails, we'll either fail
+ * immediately (for tests that expect the commit to succeed) or return the
+ * failure code (for tests that expect a specific error code).
+ */
+static int
+igt_atomic_plane_commit(igt_plane_t *plane, igt_output_t *output,
+ bool fail_on_error)
+{
+ igt_display_t *display = output->display;
+
+ uint32_t fb_id, crtc_id;
+ int ret;
+ uint32_t src_x;
+ uint32_t src_y;
+ uint32_t src_w;
+ uint32_t src_h;
+ int32_t crtc_x;
+ int32_t crtc_y;
+ uint32_t crtc_w;
+ uint32_t crtc_h;
+ drmModeAtomicReq *req;
+
+ igt_assert(plane->drm_plane);
+
+ do_or_die(drmSetClientCap(display->drm_fd, DRM_CLIENT_CAP_ATOMIC, 1));
+
+ /* it's an error to try an unsupported feature */
+ igt_assert(igt_plane_supports_rotation(plane) ||
+ !plane->rotation_changed);
+
+ fb_id = igt_plane_get_fb_id(plane);
+ crtc_id = output->config.crtc->crtc_id;
+
+ if ((plane->fb_changed || plane->size_changed) && fb_id == 0) {
+
+ LOG(display,
+ "%s: drmModeAtomicCommit pipe %s, plane %d, disabling\n",
+ igt_output_name(output),
+ kmstest_pipe_name(output->config.pipe),
+ plane->index);
+
+ req = drmModeAtomicAlloc();
+ igt_atomic_fill_plane_props(display, plane,
+ DRM_MODE_OBJECT_PLANE,
+ IGT_NUM_PLANE_PROPS,
+ igt_plane_prop_names);
+
+ drmModeAtomicSetCursor(req, 0);
+
+ /* populate plane req */
+ igt_atomic_populate_plane_req(req, plane, IGT_PLANE_CRTC_ID, crtc_id);
+
+ igt_atomic_populate_plane_req(req, plane, IGT_PLANE_SRC_X, IGT_FIXED(0, 0));
+ igt_atomic_populate_plane_req(req, plane, IGT_PLANE_SRC_Y, IGT_FIXED(0, 0));
+ igt_atomic_populate_plane_req(req, plane, IGT_PLANE_SRC_W, IGT_FIXED(0, 0));
+ igt_atomic_populate_plane_req(req, plane, IGT_PLANE_SRC_H, IGT_FIXED(0, 0));
+
+ igt_atomic_populate_plane_req(req, plane, IGT_PLANE_CRTC_X, 0);
+ igt_atomic_populate_plane_req(req, plane, IGT_PLANE_CRTC_Y, 0);
+ igt_atomic_populate_plane_req(req, plane, IGT_PLANE_CRTC_W, 0);
+ igt_atomic_populate_plane_req(req, plane, IGT_PLANE_CRTC_H, 0);
+
+ ret = drmModeAtomicCommit(display->drm_fd, req, 0, NULL);
+ drmModeAtomicFree(req);
+
+ CHECK_RETURN(ret, fail_on_error);
+
+ } else if (plane->fb_changed || plane->position_changed ||
+ plane->size_changed) {
+
+ src_x = IGT_FIXED(plane->fb->src_x,0); /* src_x */
+ src_y = IGT_FIXED(plane->fb->src_y,0); /* src_y */
+ src_w = IGT_FIXED(plane->fb->src_w,0); /* src_w */
+ src_h = IGT_FIXED(plane->fb->src_h,0); /* src_h */
+ crtc_x = plane->crtc_x;
+ crtc_y = plane->crtc_y;
+ crtc_w = plane->crtc_w;
+ crtc_h = plane->crtc_h;
+
+ LOG(display,
+ "%s: drmModeAtomicCommit %s.%d, fb %u, src = (%d, %d) "
+ "%ux%u dst = (%u, %u) %ux%u\n",
+ igt_output_name(output),
+ kmstest_pipe_name(output->config.pipe),
+ plane->index,
+ fb_id,
+ src_x >> 16, src_y >> 16, src_w >> 16, src_h >> 16,
+ crtc_x, crtc_y, crtc_w, crtc_h);
+
+
+ req = drmModeAtomicAlloc();
+ igt_atomic_fill_plane_props(display, plane,
+ DRM_MODE_OBJECT_PLANE,
+ IGT_NUM_PLANE_PROPS,
+ igt_plane_prop_names);
+
+ drmModeAtomicSetCursor(req, 0);
+
+ /* populate plane req */
+ igt_atomic_populate_plane_req(req, plane, IGT_PLANE_CRTC_ID, crtc_id);
+ igt_atomic_populate_plane_req(req, plane, IGT_PLANE_FB_ID, fb_id);
+
+ igt_atomic_populate_plane_req(req, plane, IGT_PLANE_SRC_X, src_x);
+ igt_atomic_populate_plane_req(req, plane, IGT_PLANE_SRC_Y, src_y);
+ igt_atomic_populate_plane_req(req, plane, IGT_PLANE_SRC_W, src_w);
+ igt_atomic_populate_plane_req(req, plane, IGT_PLANE_SRC_H, src_h);
+
+ igt_atomic_populate_plane_req(req, plane, IGT_PLANE_CRTC_X, crtc_x);
+ igt_atomic_populate_plane_req(req, plane, IGT_PLANE_CRTC_Y, crtc_y);
+ igt_atomic_populate_plane_req(req, plane, IGT_PLANE_CRTC_W, crtc_w);
+ igt_atomic_populate_plane_req(req, plane, IGT_PLANE_CRTC_H, crtc_h);
+
+ ret = drmModeAtomicCommit(display->drm_fd, req, 0, NULL);
+ drmModeAtomicFree(req);
+
+ CHECK_RETURN(ret, fail_on_error);
+ }
+
+ plane->fb_changed = false;
+ plane->position_changed = false;
+ plane->size_changed = false;
+
+
+ if (plane->rotation_changed) {
+ ret = igt_plane_set_property(plane, plane->rotation_property,
+ plane->rotation);
+
+ plane->rotation_changed = false;
+ CHECK_RETURN(ret, fail_on_error);
+ }
+
+ return 0;
+}
+
+
+
/*
* Commit position and fb changes to a DRM plane via the SetPlane ioctl; if the
* DRM call to program the plane fails, we'll either fail immediately (for
@@ -1558,7 +1743,10 @@ static int igt_plane_commit(igt_plane_t *plane,
return igt_primary_plane_commit_legacy(plane, output,
fail_on_error);
} else {
- return igt_drm_plane_commit(plane, output, fail_on_error);
+ if (s == COMMIT_ATOMIC)
+ return igt_atomic_plane_commit(plane, output, fail_on_error);
+ else
+ return igt_drm_plane_commit(plane, output, fail_on_error);
}
}

diff --git a/lib/igt_kms.h b/lib/igt_kms.h
index 94f315f..81d8dd7 100644
--- a/lib/igt_kms.h
+++ b/lib/igt_kms.h
@@ -156,9 +156,27 @@ void kmstest_unset_all_crtcs(int drm_fd, drmModeResPtr resources);
enum igt_commit_style {
COMMIT_LEGACY = 0,
COMMIT_UNIVERSAL,
- /* We'll add atomic here eventually. */
+ COMMIT_ATOMIC,
};

+enum igt_atomic_plane_properties {
+ IGT_PLANE_SRC_X = 0,
+ IGT_PLANE_SRC_Y,
+ IGT_PLANE_SRC_W,
+ IGT_PLANE_SRC_H,
+
+ IGT_PLANE_CRTC_X,
+ IGT_PLANE_CRTC_Y,
+ IGT_PLANE_CRTC_W,
+ IGT_PLANE_CRTC_H,
+
+ IGT_PLANE_FB_ID,
+ IGT_PLANE_CRTC_ID,
+ IGT_PLANE_TYPE,
+ IGT_NUM_PLANE_PROPS
+};
+
+
typedef struct igt_display igt_display_t;
typedef struct igt_pipe igt_pipe_t;
typedef uint32_t igt_fixed_t; /* 16.16 fixed point */
@@ -200,6 +218,7 @@ typedef struct {
/* panning offset within the fb */
unsigned int pan_x, pan_y;
igt_rotation_t rotation;
+ uint32_t atomic_props_plane[IGT_NUM_PLANE_PROPS];
} igt_plane_t;

struct igt_pipe {
@@ -281,6 +300,18 @@ void igt_wait_for_vblank(int drm_fd, enum pipe pipe);

#define IGT_FIXED(i,f) ((i) << 16 | (f))

+/**
+ * igt_atomic_populate_plane_req:
+ * @req: A pointer to drmModeAtomicReq
+ * @plane: A pointer igt_plane_t
+ * @prop: one of igt_atomic_plane_properties
+ * @value: the value to add
+ */
+#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_enable_connectors(void);
void igt_reset_connectors(void);

--
2.6.2