lib/display: Add support for the cursor plane
authorDamien Lespiau <damien.lespiau@intel.com>
Wed, 5 Feb 2014 16:36:51 +0000 (16:36 +0000)
committerDamien Lespiau <damien.lespiau@intel.com>
Tue, 11 Feb 2014 13:50:16 +0000 (13:50 +0000)
Signed-off-by: Damien Lespiau <damien.lespiau@intel.com>
lib/igt_kms.c
lib/igt_kms.h

index c9e110c..e2225e6 100644 (file)
@@ -890,16 +890,29 @@ void igt_display_init(igt_display_t *display, int drm_fd)
        for (i = 0; i < display->n_pipes; i++) {
                igt_pipe_t *pipe = &display->pipes[i];
                igt_plane_t *plane;
+               int p;
 
                pipe->display = display;
                pipe->pipe = i;
-               pipe->n_planes = 1;
 
                /* primary plane */
-               plane = &pipe->planes[0];
+               p = IGT_PLANE_PRIMARY;
+               plane = &pipe->planes[p];
                plane->pipe = pipe;
-               plane->index = 0;
+               plane->index = p;
                plane->is_primary = true;
+
+               /* cursor plane */
+               p++;
+               plane = &pipe->planes[p];
+               plane->pipe = pipe;
+               plane->index = p;
+               plane->is_cursor = true;
+
+               pipe->n_planes = ++p;
+
+               /* make sure we don't overflow the plane array */
+               igt_assert(pipe->n_planes <= IGT_MAX_PLANES);
        }
 
        /*
@@ -1010,6 +1023,22 @@ static igt_pipe_t *igt_output_get_driving_pipe(igt_output_t *output)
        return &display->pipes[pipe];
 }
 
+static igt_plane_t *igt_pipe_get_plane(igt_pipe_t *pipe, enum igt_plane plane)
+{
+       int idx;
+
+       /* Cursor plane is always the upper plane */
+       if (plane == IGT_PLANE_CURSOR)
+               idx = pipe->n_planes - 1;
+       else {
+               igt_assert_f(plane >= 0 && plane < (pipe->n_planes - 1),
+                            "plane=%d\n", plane);
+               idx = plane;
+       }
+
+       return &pipe->planes[idx];
+}
+
 static uint32_t igt_plane_get_fd_id(igt_plane_t *plane)
 {
        if (plane->fb)
@@ -1018,10 +1047,53 @@ static uint32_t igt_plane_get_fd_id(igt_plane_t *plane)
                return 0;
 }
 
+static uint32_t igt_plane_get_fb_gem_handle(igt_plane_t *plane)
+{
+       if (plane->fb)
+               return plane->fb->gem_handle;
+       else
+               return 0;
+}
+
+static int igt_cursor_commit(igt_plane_t *plane, igt_output_t *output)
+{
+       igt_display_t *display = output->display;
+       uint32_t crtc_id = output->config.crtc->crtc_id;
+       int ret;
+
+       if (plane->position_changed) {
+               int x = plane->crtc_x;
+               int y = plane->crtc_y;
+
+               LOG(display,
+                   "%s: MoveCursor pipe %c, (%d, %d)\n",
+                   igt_output_name(output),
+                   pipe_name(output->config.pipe),
+                   x, y);
+
+               ret = drmModeMoveCursor(display->drm_fd, crtc_id, x, y);
+
+               igt_assert(ret == 0);
+
+               plane->position_changed = false;
+       }
+
+       return 0;
+}
+
+static int igt_plane_commit(igt_plane_t *plane, igt_output_t *output)
+{
+       if (plane->is_cursor)
+               igt_cursor_commit(plane, output);
+
+       return 0;
+}
+
 static int igt_output_commit(igt_output_t *output)
 {
        igt_display_t *display = output->display;
        igt_pipe_t *pipe;
+       int i;
 
        pipe = igt_output_get_driving_pipe(output);
        if (pipe->need_set_crtc) {
@@ -1074,6 +1146,48 @@ static int igt_output_commit(igt_output_t *output)
                pipe->need_set_crtc = false;
        }
 
+       if (pipe->need_set_cursor) {
+               igt_plane_t *cursor;
+               uint32_t gem_handle, crtc_id;
+               int ret;
+
+               cursor = igt_pipe_get_plane(pipe, IGT_PLANE_CURSOR);
+               crtc_id = output->config.crtc->crtc_id;
+               gem_handle = igt_plane_get_fb_gem_handle(cursor);
+
+               if (gem_handle) {
+                       LOG(display,
+                           "%s: SetCursor pipe %c, fb %u %dx%d\n",
+                           igt_output_name(output),
+                           pipe_name(output->config.pipe),
+                           gem_handle,
+                           cursor->fb->width, cursor->fb->height);
+
+                       ret = drmModeSetCursor(display->drm_fd, crtc_id,
+                                              gem_handle,
+                                              cursor->fb->width,
+                                              cursor->fb->height);
+               } else {
+                       LOG(display,
+                           "%s: SetCursor pipe %c, disabling\n",
+                           igt_output_name(output),
+                           pipe_name(output->config.pipe));
+
+                       ret = drmModeSetCursor(display->drm_fd, crtc_id,
+                                              0, 0, 0);
+               }
+
+               igt_assert(ret == 0);
+
+               pipe->need_set_cursor = false;
+       }
+
+       for (i = 0; i < pipe->n_planes; i++) {
+               igt_plane_t *plane = &pipe->planes[i];
+
+               igt_plane_commit(plane, output);
+       }
+
        return 0;
 }
 
@@ -1119,12 +1233,6 @@ void igt_output_set_pipe(igt_output_t *output, enum pipe pipe)
        output->pending_crtc_idx_mask = 1 << pipe;
 }
 
-static igt_plane_t *igt_pipe_get_plane(igt_pipe_t *pipe, int index)
-{
-       igt_assert(index >= 0 && index < pipe->n_planes);
-       return &pipe->planes[index];
-}
-
 igt_plane_t *igt_ouput_get_plane(igt_output_t *output, enum igt_plane plane)
 {
        igt_pipe_t *pipe;
@@ -1145,4 +1253,26 @@ void igt_plane_set_fb(igt_plane_t *plane, struct kmstest_fb *fb)
 
        if (plane->is_primary)
                pipe->need_set_crtc = true;
+       else if (plane->is_cursor)
+               pipe->need_set_cursor = true;
+}
+
+void igt_plane_set_position(igt_plane_t *plane, int x, int y)
+{
+       igt_pipe_t *pipe = plane->pipe;
+       igt_display_t *display = pipe->display;
+
+       /*
+        * XXX: Some platforms don't need the primary plane to cover the
+        * whole pipe. Of course this test becomes wrong when we support that.
+        */
+       igt_assert(!plane->is_primary || (x == 0 && y == 0));
+
+       LOG(display, "%c.%d: plane_set_position(%d,%d)\n",
+           pipe_name(pipe->pipe), plane->index, x, y);
+
+       plane->crtc_x = x;
+       plane->crtc_y = y;
+
+       plane->position_changed = true;
 }
index bb74fc4..e86cff4 100644 (file)
@@ -109,18 +109,24 @@ uint32_t drm_format_to_bpp(uint32_t drm_format);
 
 typedef struct igt_display igt_display_t;
 typedef struct igt_pipe igt_pipe_t;
+typedef uint32_t igt_fixed_t;                  /* 16.16 fixed point */
 
 typedef struct {
        igt_pipe_t *pipe;
        int index;
-       unsigned int is_primary : 1;
+       unsigned int is_primary       : 1;
+       unsigned int is_cursor        : 1;
+       unsigned int position_changed : 1;
        struct kmstest_fb *fb;
+       /* position within pipe_src_w x pipe_src_h */
+       int crtc_x, crtc_y;
 } igt_plane_t;
 
 struct igt_pipe {
        igt_display_t *display;
        enum pipe pipe;
-       unsigned int need_set_crtc : 1;
+       unsigned int need_set_crtc   : 1;
+       unsigned int need_set_cursor : 1;
 #define IGT_MAX_PLANES 4
        int n_planes;
        igt_plane_t planes[IGT_MAX_PLANES];
@@ -158,10 +164,13 @@ void igt_output_set_pipe(igt_output_t *output, enum pipe pipe);
 igt_plane_t *igt_ouput_get_plane(igt_output_t *output, enum igt_plane plane);
 
 void igt_plane_set_fb(igt_plane_t *plane, struct kmstest_fb *fb);
+void igt_plane_set_position(igt_plane_t *plane, int x, int y);
 
 #define for_each_connected_output(display, output)             \
        for (int i__ = 0;  i__ < (display)->n_outputs; i__++)   \
                if ((output = &(display)->outputs[i__]), output->valid)
 
+#define IGT_FIXED(i,f) ((i) << 16 | (f))
+
 #endif /* __IGT_KMS_H__ */