uterm: share drm-display helpers
authorDavid Herrmann <dh.herrmann@googlemail.com>
Fri, 11 Jan 2013 18:09:42 +0000 (19:09 +0100)
committerDavid Herrmann <dh.herrmann@googlemail.com>
Fri, 11 Jan 2013 18:09:42 +0000 (19:09 +0100)
dumb and drm video backends share quite a lot of logic. Hence, move common
helpers into the drm-shared module and use it in both backends.

This also moves the uterm-display objects of both backends to use the data
member instead of static fields.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
src/uterm_drm_shared.c
src/uterm_drm_shared_internal.h
src/uterm_video_drm.c
src/uterm_video_dumb.c
src/uterm_video_internal.h

index 2c9c126..3386941 100644 (file)
@@ -191,3 +191,160 @@ int uterm_drm_get_dpms(int fd, drmModeConnector *conn)
                log_warn("display does not support DPMS");
        return UTERM_DPMS_UNKNOWN;
 }
+
+int uterm_drm_display_init(struct uterm_display *disp, void *data)
+{
+       struct uterm_drm_display *d;
+
+       d = malloc(sizeof(*d));
+       if (!d)
+               return -ENOMEM;
+       memset(d, 0, sizeof(*d));
+       disp->data = d;
+       d->data = data;
+
+       return 0;
+}
+
+void uterm_drm_display_destroy(struct uterm_display *disp)
+{
+       free(disp->data);
+}
+
+int uterm_drm_display_activate(struct uterm_display *disp, int fd)
+{
+       struct uterm_video *video = disp->video;
+       struct uterm_drm_display *ddrm = disp->data;
+       drmModeRes *res;
+       drmModeConnector *conn;
+       drmModeEncoder *enc;
+       int crtc, i;
+
+       res = drmModeGetResources(fd);
+       if (!res) {
+               log_err("cannot get resources for display %p", disp);
+               return -EFAULT;
+       }
+       conn = drmModeGetConnector(fd, ddrm->conn_id);
+       if (!conn) {
+               log_err("cannot get connector for display %p", disp);
+               drmModeFreeResources(res);
+               return -EFAULT;
+       }
+
+       crtc = -1;
+       for (i = 0; i < conn->count_encoders; ++i) {
+               enc = drmModeGetEncoder(fd, conn->encoders[i]);
+               if (!enc)
+                       continue;
+               crtc = uterm_drm_video_find_crtc(video, res, enc);
+               drmModeFreeEncoder(enc);
+               if (crtc >= 0)
+                       break;
+       }
+
+       drmModeFreeConnector(conn);
+       drmModeFreeResources(res);
+
+       if (crtc < 0) {
+               log_warn("cannot find crtc for new display");
+               return -ENODEV;
+       }
+
+       ddrm->crtc_id = crtc;
+       if (ddrm->saved_crtc)
+               drmModeFreeCrtc(ddrm->saved_crtc);
+       ddrm->saved_crtc = drmModeGetCrtc(fd, ddrm->crtc_id);
+
+       return 0;
+}
+
+void uterm_drm_display_deactivate(struct uterm_display *disp, int fd)
+{
+       struct uterm_drm_display *ddrm = disp->data;
+
+       if (ddrm->saved_crtc) {
+               if (disp->video->flags & VIDEO_AWAKE) {
+                       drmModeSetCrtc(fd, ddrm->saved_crtc->crtc_id,
+                                      ddrm->saved_crtc->buffer_id,
+                                      ddrm->saved_crtc->x,
+                                      ddrm->saved_crtc->y,
+                                      &ddrm->conn_id, 1,
+                                      &ddrm->saved_crtc->mode);
+               }
+               drmModeFreeCrtc(ddrm->saved_crtc);
+               ddrm->saved_crtc = NULL;
+       }
+
+       ddrm->crtc_id = 0;
+}
+
+int uterm_drm_display_bind(struct uterm_video *video,
+                          struct uterm_display *disp, drmModeRes *res,
+                          drmModeConnector *conn, int fd)
+{
+       struct uterm_mode *mode;
+       int ret, i;
+       struct uterm_drm_display *ddrm = disp->data;
+
+       for (i = 0; i < conn->count_modes; ++i) {
+               ret = mode_new(&mode, &uterm_drm_mode_ops);
+               if (ret)
+                       continue;
+               uterm_drm_mode_set(mode, &conn->modes[i]);
+               mode->next = disp->modes;
+               disp->modes = mode;
+
+               /* TODO: more sophisticated default-mode selection */
+               if (!disp->default_mode)
+                       disp->default_mode = mode;
+       }
+
+       if (!disp->modes) {
+               log_warn("no valid mode for display found");
+               return -EFAULT;
+       }
+
+       ddrm->conn_id = conn->connector_id;
+       disp->flags |= DISPLAY_AVAILABLE;
+       disp->next = video->displays;
+       video->displays = disp;
+       disp->dpms = uterm_drm_get_dpms(fd, conn);
+
+       log_info("display %p DPMS is %s", disp,
+                uterm_dpms_to_name(disp->dpms));
+
+       VIDEO_CB(video, disp, UTERM_NEW);
+       return 0;
+}
+
+void uterm_drm_display_unbind(struct uterm_display *disp)
+{
+       VIDEO_CB(disp->video, disp, UTERM_GONE);
+       uterm_display_deactivate(disp);
+       disp->video = NULL;
+       disp->flags &= ~DISPLAY_AVAILABLE;
+}
+
+int uterm_drm_video_find_crtc(struct uterm_video *video, drmModeRes *res,
+                             drmModeEncoder *enc)
+{
+       int i, crtc;
+       struct uterm_display *iter;
+       struct uterm_drm_display *ddrm;
+
+       for (i = 0; i < res->count_crtcs; ++i) {
+               if (enc->possible_crtcs & (1 << i)) {
+                       crtc = res->crtcs[i];
+                       for (iter = video->displays; iter; iter = iter->next) {
+                               ddrm = iter->data;
+                               if (ddrm->crtc_id == crtc)
+                                       break;
+                       }
+                       if (!iter)
+                               return crtc;
+               }
+       }
+
+       return -1;
+}
index 53d00ae..008ed96 100644 (file)
@@ -61,4 +61,34 @@ extern const struct mode_ops uterm_drm_mode_ops;
 int uterm_drm_set_dpms(int fd, uint32_t conn_id, int state);
 int uterm_drm_get_dpms(int fd, drmModeConnector *conn);
 
+/* drm display */
+
+struct uterm_drm_display {
+       uint32_t conn_id;
+       int crtc_id;
+       drmModeCrtc *saved_crtc;
+       void *data;
+};
+
+int uterm_drm_display_init(struct uterm_display *disp, void *data);
+void uterm_drm_display_destroy(struct uterm_display *disp);
+int uterm_drm_display_activate(struct uterm_display *disp, int fd);
+void uterm_drm_display_deactivate(struct uterm_display *disp, int fd);
+int uterm_drm_display_bind(struct uterm_video *video,
+                          struct uterm_display *disp, drmModeRes *res,
+                          drmModeConnector *conn, int fd);
+void uterm_drm_display_unbind(struct uterm_display *disp);
+
+static inline void *uterm_drm_display_get_data(struct uterm_display *disp)
+{
+       struct uterm_drm_display *d = disp->data;
+
+       return d->data;
+}
+
+/* drm video */
+
+int uterm_drm_video_find_crtc(struct uterm_video *video, drmModeRes *res,
+                             drmModeEncoder *enc);
+
 #endif /* UTERM_DRM_SHARED_INTERNAL_H */
index 1cfec3b..2c22543 100644 (file)
 
 #define LOG_SUBSYSTEM "video_drm"
 
+struct uterm_drm3d_rb {
+       struct uterm_display *disp;
+       struct gbm_bo *bo;
+       uint32_t fb;
+};
+
+struct uterm_drm3d_display {
+       struct gbm_surface *gbm;
+       EGLSurface surface;
+       struct uterm_drm3d_rb *current;
+       struct uterm_drm3d_rb *next;
+       unsigned int ignore_flips;
+};
+
+static int display_init(struct uterm_display *disp)
+{
+       struct uterm_drm3d_display *d3d;
+       int ret;
+
+       d3d = malloc(sizeof(*d3d));
+       if (!d3d)
+               return -ENOMEM;
+       memset(d3d, 0, sizeof(*d3d));
+
+       ret = uterm_drm_display_init(disp, d3d);
+       if (ret) {
+               free(d3d);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void display_destroy(struct uterm_display *disp)
+{
+       free(uterm_drm_display_get_data(disp));
+       uterm_drm_display_destroy(disp);
+}
+
 static void bo_destroy_event(struct gbm_bo *bo, void *data)
 {
-       struct drm_rb *rb = data;
+       struct uterm_drm3d_rb *rb = data;
 
        if (!rb)
                return;
@@ -63,9 +102,10 @@ static void bo_destroy_event(struct gbm_bo *bo, void *data)
        free(rb);
 }
 
-static struct drm_rb *bo_to_rb(struct uterm_display *disp, struct gbm_bo *bo)
+static struct uterm_drm3d_rb *bo_to_rb(struct uterm_display *disp,
+                                      struct gbm_bo *bo)
 {
-       struct drm_rb *rb = gbm_bo_get_user_data(bo);
+       struct uterm_drm3d_rb *rb = gbm_bo_get_user_data(bo);
        struct uterm_video *video = disp->video;
        int ret;
        unsigned int stride, handle, width, height;;
@@ -103,34 +143,13 @@ static struct drm_rb *bo_to_rb(struct uterm_display *disp, struct gbm_bo *bo)
        return rb;
 }
 
-static int find_crtc(struct uterm_video *video, drmModeRes *res,
-                                                       drmModeEncoder *enc)
-{
-       int i, crtc;
-       struct uterm_display *iter;
-
-       for (i = 0; i < res->count_crtcs; ++i) {
-               if (enc->possible_crtcs & (1 << i)) {
-                       crtc = res->crtcs[i];
-                       for (iter = video->displays; iter; iter = iter->next) {
-                               if (iter->drm.crtc_id == crtc)
-                                       break;
-                       }
-                       if (!iter)
-                               return crtc;
-               }
-       }
-
-       return -1;
-}
-
-static int display_activate(struct uterm_display *disp, struct uterm_mode *mode)
+static int display_activate(struct uterm_display *disp,
+                           struct uterm_mode *mode)
 {
        struct uterm_video *video = disp->video;
-       int ret, crtc, i;
-       drmModeRes *res;
-       drmModeConnector *conn;
-       drmModeEncoder *enc;
+       struct uterm_drm_display *ddrm = disp->data;
+       struct uterm_drm3d_display *d3d = uterm_drm_display_get_data(disp);
+       int ret;
        struct gbm_bo *bo;
        drmModeModeInfo *minfo;
 
@@ -143,67 +162,35 @@ static int display_activate(struct uterm_display *disp, struct uterm_mode *mode)
        log_info("activating display %p to %ux%u", disp,
                 minfo->hdisplay, minfo->vdisplay);
 
-       res = drmModeGetResources(video->drm.fd);
-       if (!res) {
-               log_err("cannot get resources for display %p", disp);
-               return -EFAULT;
-       }
-       conn = drmModeGetConnector(video->drm.fd, disp->drm.conn_id);
-       if (!conn) {
-               log_err("cannot get connector for display %p", disp);
-               drmModeFreeResources(res);
-               return -EFAULT;
-       }
-
-       crtc = -1;
-       for (i = 0; i < conn->count_encoders; ++i) {
-               enc = drmModeGetEncoder(video->drm.fd, conn->encoders[i]);
-               if (!enc)
-                       continue;
-               crtc = find_crtc(video, res, enc);
-               drmModeFreeEncoder(enc);
-               if (crtc >= 0)
-                       break;
-       }
-
-       drmModeFreeConnector(conn);
-       drmModeFreeResources(res);
-
-       if (crtc < 0) {
-               log_warn("cannot find crtc for new display");
-               return -ENODEV;
-       }
+       ret = uterm_drm_display_activate(disp, video->drm.fd);
+       if (ret)
+               return ret;
 
-       disp->drm.crtc_id = crtc;
-       disp->drm.current = NULL;
-       disp->drm.next = NULL;
+       d3d->current = NULL;
+       d3d->next = NULL;
        disp->current_mode = mode;
-       disp->drm.saved_crtc = drmModeGetCrtc(video->drm.fd,
-                                             disp->drm.crtc_id);
-
-       disp->drm.gbm = gbm_surface_create(video->drm.gbm,
-                                          minfo->hdisplay, minfo->vdisplay,
-                                          GBM_FORMAT_XRGB8888,
-                                          GBM_BO_USE_SCANOUT |
-                                          GBM_BO_USE_RENDERING);
-       if (!disp->drm.gbm) {
+
+       d3d->gbm = gbm_surface_create(video->drm.gbm, minfo->hdisplay,
+                                     minfo->vdisplay, GBM_FORMAT_XRGB8888,
+                                     GBM_BO_USE_SCANOUT |
+                                     GBM_BO_USE_RENDERING);
+       if (!d3d->gbm) {
                log_error("cannot create gbm surface (%d): %m", errno);
                ret = -EFAULT;
                goto err_saved;
        }
 
-       disp->drm.surface = eglCreateWindowSurface(video->drm.disp,
-                                                  video->drm.conf,
-                                                  (EGLNativeWindowType)disp->drm.gbm,
-                                                  NULL);
-       if (disp->drm.surface == EGL_NO_SURFACE) {
+       d3d->surface = eglCreateWindowSurface(video->drm.disp, video->drm.conf,
+                                             (EGLNativeWindowType)d3d->gbm,
+                                             NULL);
+       if (d3d->surface == EGL_NO_SURFACE) {
                log_error("cannot create EGL window surface");
                ret = -EFAULT;
                goto err_gbm;
        }
 
-       if (!eglMakeCurrent(video->drm.disp, disp->drm.surface,
-                           disp->drm.surface, video->drm.ctx)) {
+       if (!eglMakeCurrent(video->drm.disp, d3d->surface, d3d->surface,
+                           video->drm.ctx)) {
                log_error("cannot activate EGL context");
                ret = -EFAULT;
                goto err_surface;
@@ -211,29 +198,28 @@ static int display_activate(struct uterm_display *disp, struct uterm_mode *mode)
 
        glClearColor(0, 0, 0, 0);
        glClear(GL_COLOR_BUFFER_BIT);
-       if (!eglSwapBuffers(video->drm.disp, disp->drm.surface)) {
+       if (!eglSwapBuffers(video->drm.disp, d3d->surface)) {
                log_error("cannot swap buffers");
                ret = -EFAULT;
                goto err_noctx;
        }
 
-       bo = gbm_surface_lock_front_buffer(disp->drm.gbm);
+       bo = gbm_surface_lock_front_buffer(d3d->gbm);
        if (!bo) {
                log_error("cannot lock front buffer during creation");
                ret = -EFAULT;
                goto err_noctx;
        }
 
-       disp->drm.current = bo_to_rb(disp, bo);
-       if (!disp->drm.current) {
+       d3d->current = bo_to_rb(disp, bo);
+       if (!d3d->current) {
                log_error("cannot lock front buffer");
                ret = -EFAULT;
                goto err_bo;
        }
 
-       ret = drmModeSetCrtc(video->drm.fd, disp->drm.crtc_id,
-                            disp->drm.current->fb, 0, 0, &disp->drm.conn_id, 1,
-                            minfo);
+       ret = drmModeSetCrtc(video->drm.fd, ddrm->crtc_id, d3d->current->fb,
+                            0, 0, &ddrm->conn_id, 1, minfo);
        if (ret) {
                log_err("cannot set drm-crtc");
                ret = -EFAULT;
@@ -244,69 +230,56 @@ static int display_activate(struct uterm_display *disp, struct uterm_mode *mode)
        return 0;
 
 err_bo:
-       gbm_surface_release_buffer(disp->drm.gbm, bo);
+       gbm_surface_release_buffer(d3d->gbm, bo);
 err_noctx:
        eglMakeCurrent(video->drm.disp, EGL_NO_SURFACE, EGL_NO_SURFACE,
                       video->drm.ctx);
 err_surface:
-       eglDestroySurface(video->drm.disp, disp->drm.surface);
+       eglDestroySurface(video->drm.disp, d3d->surface);
 err_gbm:
-       gbm_surface_destroy(disp->drm.gbm);
+       gbm_surface_destroy(d3d->gbm);
 err_saved:
-       disp->drm.crtc_id = 0;
        disp->current_mode = NULL;
-       if (disp->drm.saved_crtc) {
-               drmModeFreeCrtc(disp->drm.saved_crtc);
-               disp->drm.saved_crtc = NULL;
-       }
+       uterm_drm_display_deactivate(disp, video->drm.fd);
        return ret;
 }
 
 static void display_deactivate(struct uterm_display *disp)
 {
+       struct uterm_drm3d_display *d3d = uterm_drm_display_get_data(disp);
+       struct uterm_video *video = disp->video;
 
        if (!display_is_online(disp))
                return;
 
-       if (disp->drm.saved_crtc) {
-               if (disp->video->flags & VIDEO_AWAKE) {
-                       drmModeSetCrtc(disp->video->drm.fd,
-                                       disp->drm.saved_crtc->crtc_id,
-                                       disp->drm.saved_crtc->buffer_id,
-                                       disp->drm.saved_crtc->x,
-                                       disp->drm.saved_crtc->y,
-                                       &disp->drm.conn_id,
-                                       1,
-                                       &disp->drm.saved_crtc->mode);
-               }
-               drmModeFreeCrtc(disp->drm.saved_crtc);
-               disp->drm.saved_crtc = NULL;
-       }
+       log_info("deactivating display %p", disp);
 
-       eglMakeCurrent(disp->video->drm.disp, EGL_NO_SURFACE, EGL_NO_SURFACE,
-                      disp->video->drm.ctx);
-       eglDestroySurface(disp->video->drm.disp, disp->drm.surface);
+       uterm_drm_display_deactivate(disp, disp->video->drm.fd);
 
-       if (disp->drm.current) {
-               gbm_surface_release_buffer(disp->drm.gbm,
-                                          disp->drm.current->bo);
-               disp->drm.current = NULL;
+       eglMakeCurrent(video->drm.disp, EGL_NO_SURFACE, EGL_NO_SURFACE,
+                      video->drm.ctx);
+       eglDestroySurface(video->drm.disp, d3d->surface);
+
+       if (d3d->current) {
+               gbm_surface_release_buffer(d3d->gbm,
+                                          d3d->current->bo);
+               d3d->current = NULL;
        }
-       if (disp->drm.next) {
-               gbm_surface_release_buffer(disp->drm.gbm,
-                                          disp->drm.next->bo);
-               disp->drm.next = NULL;
+       if (d3d->next) {
+               gbm_surface_release_buffer(d3d->gbm,
+                                          d3d->next->bo);
+               d3d->next = NULL;
        }
 
-       gbm_surface_destroy(disp->drm.gbm);
+       gbm_surface_destroy(d3d->gbm);
        disp->current_mode = NULL;
        disp->flags &= ~(DISPLAY_ONLINE | DISPLAY_VSYNC);
-       log_info("deactivating display %p", disp);
 }
 
 static int display_set_dpms(struct uterm_display *disp, int state)
 {
        int ret;
+       struct uterm_drm_display *ddrm = disp->data;
 
        if (!display_is_conn(disp) || !video_is_awake(disp->video))
                return -EINVAL;
@@ -314,8 +287,7 @@ static int display_set_dpms(struct uterm_display *disp, int state)
        log_info("setting DPMS of display %p to %s", disp,
                 uterm_dpms_to_name(state));
 
-       ret = uterm_drm_set_dpms(disp->video->drm.fd, disp->drm.conn_id,
-                                state);
+       ret = uterm_drm_set_dpms(disp->video->drm.fd, ddrm->conn_id, state);
        if (ret < 0)
                return ret;
 
@@ -325,11 +297,13 @@ static int display_set_dpms(struct uterm_display *disp, int state)
 
 static int display_use(struct uterm_display *disp)
 {
+       struct uterm_drm3d_display *d3d = uterm_drm_display_get_data(disp);
+
        if (!display_is_online(disp))
                return -EINVAL;
 
-       if (!eglMakeCurrent(disp->video->drm.disp, disp->drm.surface,
-                           disp->drm.surface, disp->video->drm.ctx)) {
+       if (!eglMakeCurrent(disp->video->drm.disp, d3d->surface,
+                           d3d->surface, disp->video->drm.ctx)) {
                log_error("cannot activate EGL context");
                return -EFAULT;
        }
@@ -341,14 +315,16 @@ static int swap_display(struct uterm_display *disp, bool immediate)
 {
        int ret;
        struct gbm_bo *bo;
-       struct drm_rb *rb;
+       struct uterm_drm3d_rb *rb;
+       struct uterm_drm3d_display *d3d = uterm_drm_display_get_data(disp);
+       struct uterm_drm_display *ddrm = disp->data;
 
        if (!display_is_online(disp) || !video_is_awake(disp->video))
                return -EINVAL;
        if (disp->dpms != UTERM_DPMS_ON)
                return -EINVAL;
        if (!immediate &&
-           ((disp->flags & DISPLAY_VSYNC) || disp->drm.ignore_flips))
+           ((disp->flags & DISPLAY_VSYNC) || d3d->ignore_flips))
                return -EBUSY;
 
        /* TODO: immediate page-flips are somewhat buggy and can cause
@@ -362,31 +338,29 @@ static int swap_display(struct uterm_display *disp, bool immediate)
                return 0;
        }
 
-       if (!gbm_surface_has_free_buffers(disp->drm.gbm)) {
-               if (disp->drm.next) {
+       if (!gbm_surface_has_free_buffers(d3d->gbm)) {
+               if (d3d->next) {
                        log_debug("no free buffer, releasing next-buffer");
-                       gbm_surface_release_buffer(disp->drm.gbm,
-                                                  disp->drm.next->bo);
-                       disp->drm.next = NULL;
-               } else if (disp->drm.current) {
+                       gbm_surface_release_buffer(d3d->gbm, d3d->next->bo);
+                       d3d->next = NULL;
+               } else if (d3d->current) {
                        log_debug("no free buffer, releasing current-buffer");
-                       gbm_surface_release_buffer(disp->drm.gbm,
-                                                  disp->drm.current->bo);
-                       disp->drm.current = NULL;
+                       gbm_surface_release_buffer(d3d->gbm, d3d->current->bo);
+                       d3d->current = NULL;
                }
 
-               if (!gbm_surface_has_free_buffers(disp->drm.gbm)) {
+               if (!gbm_surface_has_free_buffers(d3d->gbm)) {
                        log_warning("gbm ran out of free buffers");
                        return -EFAULT;
                }
        }
 
-       if (!eglSwapBuffers(disp->video->drm.disp, disp->drm.surface)) {
+       if (!eglSwapBuffers(disp->video->drm.disp, d3d->surface)) {
                log_error("cannot swap EGL buffers (%d): %m", errno);
                return -EFAULT;
        }
 
-       bo = gbm_surface_lock_front_buffer(disp->drm.gbm);
+       bo = gbm_surface_lock_front_buffer(d3d->gbm);
        if (!bo) {
                log_error("cannot lock front buffer");
                return -EFAULT;
@@ -395,47 +369,45 @@ static int swap_display(struct uterm_display *disp, bool immediate)
        rb = bo_to_rb(disp, bo);
        if (!rb) {
                log_error("cannot lock front gbm buffer (%d): %m", errno);
-               gbm_surface_release_buffer(disp->drm.gbm, bo);
+               gbm_surface_release_buffer(d3d->gbm, bo);
                return -EFAULT;
        }
 
        if (immediate) {
-               ret = drmModeSetCrtc(disp->video->drm.fd, disp->drm.crtc_id,
-                                    rb->fb, 0, 0, &disp->drm.conn_id, 1,
+               ret = drmModeSetCrtc(disp->video->drm.fd, ddrm->crtc_id,
+                                    rb->fb, 0, 0, &ddrm->conn_id, 1,
                                     uterm_drm_mode_get_info(disp->current_mode));
                if (ret) {
                        log_err("cannot set drm-crtc");
-                       gbm_surface_release_buffer(disp->drm.gbm, bo);
+                       gbm_surface_release_buffer(d3d->gbm, bo);
                        return -EFAULT;
                }
 
-               if (disp->drm.current) {
-                       gbm_surface_release_buffer(disp->drm.gbm,
-                                                  disp->drm.current->bo);
-                       disp->drm.current = NULL;
+               if (d3d->current) {
+                       gbm_surface_release_buffer(d3d->gbm, d3d->current->bo);
+                       d3d->current = NULL;
                }
-               if (disp->drm.next) {
-                       gbm_surface_release_buffer(disp->drm.gbm,
-                                                  disp->drm.next->bo);
-                       disp->drm.next = NULL;
+               if (d3d->next) {
+                       gbm_surface_release_buffer(d3d->gbm, d3d->next->bo);
+                       d3d->next = NULL;
                }
-               disp->drm.current = rb;
+               d3d->current = rb;
 
                if (disp->flags & DISPLAY_VSYNC) {
                        disp->flags &= ~DISPLAY_VSYNC;
-                       disp->drm.ignore_flips++;
+                       d3d->ignore_flips++;
                        DISPLAY_CB(disp, UTERM_PAGE_FLIP);
                }
        } else {
-               ret = drmModePageFlip(disp->video->drm.fd, disp->drm.crtc_id,
+               ret = drmModePageFlip(disp->video->drm.fd, ddrm->crtc_id,
                                      rb->fb, DRM_MODE_PAGE_FLIP_EVENT, disp);
                if (ret) {
                        log_warn("page-flip failed %d %d", ret, errno);
-                       gbm_surface_release_buffer(disp->drm.gbm, bo);
+                       gbm_surface_release_buffer(d3d->gbm, bo);
                        return -EFAULT;
                }
 
-               disp->drm.next = rb;
+               d3d->next = rb;
                uterm_display_ref(disp);
                disp->flags |= DISPLAY_VSYNC;
        }
@@ -900,8 +872,8 @@ static int display_fill(struct uterm_display *disp,
 }
 
 static const struct display_ops drm_display_ops = {
-       .init = NULL,
-       .destroy = NULL,
+       .init = display_init,
+       .destroy = display_destroy,
        .activate = display_activate,
        .deactivate = display_deactivate,
        .set_dpms = display_set_dpms,
@@ -937,43 +909,20 @@ static void show_displays(struct uterm_video *video)
 }
 
 static void bind_display(struct uterm_video *video, drmModeRes *res,
-                                                       drmModeConnector *conn)
+                        drmModeConnector *conn)
 {
        struct uterm_display *disp;
-       struct uterm_mode *mode;
-       int ret, i;
+       int ret;
 
        ret = display_new(&disp, &drm_display_ops, video);
        if (ret)
                return;
 
-       for (i = 0; i < conn->count_modes; ++i) {
-               ret = mode_new(&mode, &uterm_drm_mode_ops);
-               if (ret)
-                       continue;
-               uterm_drm_mode_set(mode, &conn->modes[i]);
-               mode->next = disp->modes;
-               disp->modes = mode;
-
-               /* TODO: more sophisticated default-mode selection */
-               if (!disp->default_mode)
-                       disp->default_mode = mode;
-       }
-
-       if (!disp->modes) {
-               log_warn("no valid mode for display found");
+       ret = uterm_drm_display_bind(video, disp, res, conn, video->drm.fd);
+       if (ret) {
                uterm_display_unref(disp);
                return;
        }
-
-       disp->drm.conn_id = conn->connector_id;
-       disp->flags |= DISPLAY_AVAILABLE;
-       disp->next = video->displays;
-       video->displays = disp;
-       disp->dpms = uterm_drm_get_dpms(disp->video->drm.fd, conn);
-       log_info("display %p DPMS is %s", disp,
-                       uterm_dpms_to_name(disp->dpms));
-       VIDEO_CB(video, disp, UTERM_NEW);
 }
 
 static void unbind_display(struct uterm_display *disp)
@@ -981,10 +930,7 @@ static void unbind_display(struct uterm_display *disp)
        if (!display_is_conn(disp))
                return;
 
-       VIDEO_CB(disp->video, disp, UTERM_GONE);
-       display_deactivate(disp);
-       disp->video = NULL;
-       disp->flags &= ~DISPLAY_AVAILABLE;
+       uterm_drm_display_unbind(disp);
        uterm_display_unref(disp);
 }
 
@@ -992,17 +938,18 @@ static void page_flip_handler(int fd, unsigned int frame, unsigned int sec,
                              unsigned int usec, void *data)
 {
        struct uterm_display *disp = data;
+       struct uterm_drm3d_display *d3d = uterm_drm_display_get_data(disp);
 
-       if (disp->drm.ignore_flips) {
-               --disp->drm.ignore_flips;
+       if (d3d->ignore_flips) {
+               --d3d->ignore_flips;
        } else if (disp->flags & DISPLAY_VSYNC) {
                disp->flags &= ~DISPLAY_VSYNC;
-               if (disp->drm.next) {
-                       if (disp->drm.current)
-                               gbm_surface_release_buffer(disp->drm.gbm,
-                                                          disp->drm.current->bo);
-                       disp->drm.current = disp->drm.next;
-                       disp->drm.next = NULL;
+               if (d3d->next) {
+                       if (d3d->current)
+                               gbm_surface_release_buffer(d3d->gbm,
+                                                          d3d->current->bo);
+                       d3d->current = d3d->next;
+                       d3d->next = NULL;
                }
                DISPLAY_CB(disp, UTERM_PAGE_FLIP);
        }
@@ -1193,6 +1140,7 @@ static int hotplug(struct uterm_video *video)
        drmModeRes *res;
        drmModeConnector *conn;
        struct uterm_display *disp, *tmp;
+       struct uterm_drm_display *ddrm;
        int i;
 
        if (!video_is_awake(video) || !video_need_hotplug(video))
@@ -1213,7 +1161,8 @@ static int hotplug(struct uterm_video *video)
                        continue;
                if (conn->connection == DRM_MODE_CONNECTED) {
                        for (disp = video->displays; disp; disp = disp->next) {
-                               if (disp->drm.conn_id == res->connectors[i]) {
+                               ddrm = disp->data;
+                               if (ddrm->conn_id == res->connectors[i]) {
                                        disp->flags |= DISPLAY_AVAILABLE;
                                        break;
                                }
index 4333e85..941f5a9 100644 (file)
 
 #define LOG_SUBSYSTEM "video_dumb"
 
-static int init_rb(struct uterm_display *disp, struct dumb_rb *rb)
+struct uterm_drm2d_rb {
+       uint32_t fb;
+       uint32_t handle;
+       uint32_t stride;
+       uint64_t size;
+       void *map;
+};
+
+struct uterm_drm2d_display {
+       int current_rb;
+       struct uterm_drm2d_rb rb[2];
+};
+
+static int display_init(struct uterm_display *disp)
+{
+       struct uterm_drm2d_display *d2d;
+       int ret;
+
+       d2d = malloc(sizeof(*d2d));
+       if (!d2d)
+               return -ENOMEM;
+       memset(d2d, 0, sizeof(*d2d));
+
+       ret = uterm_drm_display_init(disp, d2d);
+       if (ret) {
+               free(d2d);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void display_destroy(struct uterm_display *disp)
+{
+       free(uterm_drm_display_get_data(disp));
+       uterm_drm_display_destroy(disp);
+}
+
+static int init_rb(struct uterm_display *disp, struct uterm_drm2d_rb *rb)
 {
        int ret;
        struct uterm_video *video = disp->video;
@@ -111,7 +149,7 @@ err_buf:
        return ret;
 }
 
-static void destroy_rb(struct uterm_display *disp, struct dumb_rb *rb)
+static void destroy_rb(struct uterm_display *disp, struct uterm_drm2d_rb *rb)
 {
        struct drm_mode_destroy_dumb dreq;
        int ret;
@@ -127,34 +165,12 @@ static void destroy_rb(struct uterm_display *disp, struct dumb_rb *rb)
                            ret, errno);
 }
 
-static int find_crtc(struct uterm_video *video, drmModeRes *res,
-                                                       drmModeEncoder *enc)
-{
-       int i, crtc;
-       struct uterm_display *iter;
-
-       for (i = 0; i < res->count_crtcs; ++i) {
-               if (enc->possible_crtcs & (1 << i)) {
-                       crtc = res->crtcs[i];
-                       for (iter = video->displays; iter; iter = iter->next) {
-                               if (iter->dumb.crtc_id == crtc)
-                                       break;
-                       }
-                       if (!iter)
-                               return crtc;
-               }
-       }
-
-       return -1;
-}
-
 static int display_activate(struct uterm_display *disp, struct uterm_mode *mode)
 {
        struct uterm_video *video = disp->video;
-       int ret, crtc, i;
-       drmModeRes *res;
-       drmModeConnector *conn;
-       drmModeEncoder *enc;
+       struct uterm_drm_display *ddrm = disp->data;
+       struct uterm_drm2d_display *d2d = uterm_drm_display_get_data(disp);
+       int ret;
        drmModeModeInfo *minfo;
 
        if (!video || !video_is_awake(video) || !mode)
@@ -166,54 +182,24 @@ static int display_activate(struct uterm_display *disp, struct uterm_mode *mode)
        log_info("activating display %p to %ux%u", disp,
                 minfo->hdisplay, minfo->vdisplay);
 
-       res = drmModeGetResources(video->dumb.fd);
-       if (!res) {
-               log_err("cannot get resources for display %p", disp);
-               return -EFAULT;
-       }
-       conn = drmModeGetConnector(video->dumb.fd, disp->dumb.conn_id);
-       if (!conn) {
-               log_err("cannot get connector for display %p", disp);
-               drmModeFreeResources(res);
-               return -EFAULT;
-       }
-
-       crtc = -1;
-       for (i = 0; i < conn->count_encoders; ++i) {
-               enc = drmModeGetEncoder(video->dumb.fd, conn->encoders[i]);
-               if (!enc)
-                       continue;
-               crtc = find_crtc(video, res, enc);
-               drmModeFreeEncoder(enc);
-               if (crtc >= 0)
-                       break;
-       }
-
-       drmModeFreeConnector(conn);
-       drmModeFreeResources(res);
-
-       if (crtc < 0) {
-               log_warn("cannot find crtc for new display");
-               return -ENODEV;
-       }
+       ret = uterm_drm_display_activate(disp, video->dumb.fd);
+       if (ret)
+               return ret;
 
-       disp->dumb.crtc_id = crtc;
-       disp->dumb.current_rb = 0;
+       d2d->current_rb = 0;
        disp->current_mode = mode;
-       disp->dumb.saved_crtc = drmModeGetCrtc(video->dumb.fd,
-                                              disp->dumb.crtc_id);
 
-       ret = init_rb(disp, &disp->dumb.rb[0]);
+       ret = init_rb(disp, &d2d->rb[0]);
        if (ret)
                goto err_saved;
 
-       ret = init_rb(disp, &disp->dumb.rb[1]);
+       ret = init_rb(disp, &d2d->rb[1]);
        if (ret)
                goto err_rb;
 
-       ret = drmModeSetCrtc(video->dumb.fd, disp->dumb.crtc_id,
-                       disp->dumb.rb[0].fb, 0, 0, &disp->dumb.conn_id, 1,
-                       minfo);
+       ret = drmModeSetCrtc(video->dumb.fd, ddrm->crtc_id,
+                            d2d->rb[0].fb, 0, 0, &ddrm->conn_id, 1,
+                            minfo);
        if (ret) {
                log_err("cannot set drm-crtc");
                ret = -EFAULT;
@@ -224,48 +210,36 @@ static int display_activate(struct uterm_display *disp, struct uterm_mode *mode)
        return 0;
 
 err_fb:
-       destroy_rb(disp, &disp->dumb.rb[1]);
+       destroy_rb(disp, &d2d->rb[1]);
 err_rb:
-       destroy_rb(disp, &disp->dumb.rb[0]);
+       destroy_rb(disp, &d2d->rb[0]);
 err_saved:
        disp->current_mode = NULL;
-       if (disp->dumb.saved_crtc) {
-               drmModeFreeCrtc(disp->dumb.saved_crtc);
-               disp->dumb.saved_crtc = NULL;
-       }
+       uterm_drm_display_deactivate(disp, video->dumb.fd);
        return ret;
 }
 
 static void display_deactivate(struct uterm_display *disp)
 {
+       struct uterm_drm2d_display *d2d = uterm_drm_display_get_data(disp);
+
        if (!display_is_online(disp))
                return;
 
-       if (disp->dumb.saved_crtc) {
-               if (disp->video->flags & VIDEO_AWAKE) {
-                       drmModeSetCrtc(disp->video->dumb.fd,
-                                       disp->dumb.saved_crtc->crtc_id,
-                                       disp->dumb.saved_crtc->buffer_id,
-                                       disp->dumb.saved_crtc->x,
-                                       disp->dumb.saved_crtc->y,
-                                       &disp->dumb.conn_id,
-                                       1,
-                                       &disp->dumb.saved_crtc->mode);
-               }
-               drmModeFreeCrtc(disp->dumb.saved_crtc);
-               disp->dumb.saved_crtc = NULL;
-       }
+       log_info("deactivating display %p", disp);
+
+       uterm_drm_display_deactivate(disp, disp->video->dumb.fd);
 
-       destroy_rb(disp, &disp->dumb.rb[1]);
-       destroy_rb(disp, &disp->dumb.rb[0]);
+       destroy_rb(disp, &d2d->rb[1]);
+       destroy_rb(disp, &d2d->rb[0]);
        disp->current_mode = NULL;
        disp->flags &= ~(DISPLAY_ONLINE | DISPLAY_VSYNC);
-       log_info("deactivating display %p", disp);
 }
 
 static int display_set_dpms(struct uterm_display *disp, int state)
 {
        int ret;
+       struct uterm_drm_display *ddrm = disp->data;
 
        if (!display_is_conn(disp) || !video_is_awake(disp->video))
                return -EINVAL;
@@ -273,8 +247,7 @@ static int display_set_dpms(struct uterm_display *disp, int state)
        log_info("setting DPMS of display %p to %s", disp,
                 uterm_dpms_to_name(state));
 
-       ret = uterm_drm_set_dpms(disp->video->dumb.fd, disp->dumb.conn_id,
-                                state);
+       ret = uterm_drm_set_dpms(disp->video->dumb.fd, ddrm->conn_id, state);
        if (ret < 0)
                return ret;
 
@@ -285,6 +258,8 @@ static int display_set_dpms(struct uterm_display *disp, int state)
 static int display_swap(struct uterm_display *disp)
 {
        int ret;
+       struct uterm_drm_display *ddrm = disp->data;
+       struct uterm_drm2d_display *d2d = uterm_drm_display_get_data(disp);
 
        if (!display_is_online(disp) || !video_is_awake(disp->video))
                return -EINVAL;
@@ -292,10 +267,10 @@ static int display_swap(struct uterm_display *disp)
                return -EINVAL;
 
        errno = 0;
-       disp->dumb.current_rb ^= 1;
-       ret = drmModePageFlip(disp->video->dumb.fd, disp->dumb.crtc_id,
-                               disp->dumb.rb[disp->dumb.current_rb].fb,
-                               DRM_MODE_PAGE_FLIP_EVENT, disp);
+       d2d->current_rb ^= 1;
+       ret = drmModePageFlip(disp->video->dumb.fd, ddrm->crtc_id,
+                             d2d->rb[d2d->current_rb].fb,
+                             DRM_MODE_PAGE_FLIP_EVENT, disp);
        if (ret) {
                log_warn("page-flip failed %d %d", ret, errno);
                return -EFAULT;
@@ -312,9 +287,10 @@ static int display_blit(struct uterm_display *disp,
 {
        unsigned int tmp;
        uint8_t *dst, *src;
-       struct dumb_rb *rb;
        unsigned int width, height;
        unsigned int sw, sh;
+       struct uterm_drm2d_rb *rb;
+       struct uterm_drm2d_display *d2d = uterm_drm_display_get_data(disp);
 
        if (!disp->video || !display_is_online(disp))
                return -EINVAL;
@@ -323,7 +299,7 @@ static int display_blit(struct uterm_display *disp,
        if (buf->format != UTERM_FORMAT_XRGB32)
                return -EINVAL;
 
-       rb = &disp->dumb.rb[disp->dumb.current_rb ^ 1];
+       rb = &d2d->rb[d2d->current_rb ^ 1];
        sw = uterm_drm_mode_get_width(disp->current_mode);
        sh = uterm_drm_mode_get_height(disp->current_mode);
 
@@ -362,17 +338,18 @@ static int display_fake_blendv(struct uterm_display *disp,
 {
        unsigned int tmp;
        uint8_t *dst, *src;
-       struct dumb_rb *rb;
        unsigned int width, height, i, j;
        unsigned int sw, sh;
        unsigned int r, g, b;
+       struct uterm_drm2d_rb *rb;
+       struct uterm_drm2d_display *d2d = uterm_drm_display_get_data(disp);
 
        if (!disp->video || !display_is_online(disp))
                return -EINVAL;
        if (!req || !video_is_awake(disp->video))
                return -EINVAL;
 
-       rb = &disp->dumb.rb[disp->dumb.current_rb ^ 1];
+       rb = &d2d->rb[d2d->current_rb ^ 1];
        sw = uterm_drm_mode_get_width(disp->current_mode);
        sh = uterm_drm_mode_get_height(disp->current_mode);
 
@@ -445,15 +422,16 @@ static int display_fill(struct uterm_display *disp,
 {
        unsigned int tmp, i;
        uint8_t *dst;
-       struct dumb_rb *rb;
        unsigned int sw, sh;
+       struct uterm_drm2d_rb *rb;
+       struct uterm_drm2d_display *d2d = uterm_drm_display_get_data(disp);
 
        if (!disp->video || !(disp->flags & DISPLAY_ONLINE))
                return -EINVAL;
        if (!video_is_awake(disp->video))
                return -EINVAL;
 
-       rb = &disp->dumb.rb[disp->dumb.current_rb ^ 1];
+       rb = &d2d->rb[d2d->current_rb ^ 1];
        sw = uterm_drm_mode_get_width(disp->current_mode);
        sh = uterm_drm_mode_get_height(disp->current_mode);
 
@@ -481,8 +459,8 @@ static int display_fill(struct uterm_display *disp,
 }
 
 static const struct display_ops dumb_display_ops = {
-       .init = NULL,
-       .destroy = NULL,
+       .init = display_init,
+       .destroy = display_destroy,
        .activate = display_activate,
        .deactivate = display_deactivate,
        .set_dpms = display_set_dpms,
@@ -497,7 +475,9 @@ static void show_displays(struct uterm_video *video)
 {
        int ret;
        struct uterm_display *iter;
-       struct dumb_rb *rb;
+       struct uterm_drm_display *ddrm;
+       struct uterm_drm2d_display *d2d;
+       struct uterm_drm2d_rb *rb;
 
        if (!video_is_awake(video))
                return;
@@ -508,10 +488,13 @@ static void show_displays(struct uterm_video *video)
                if (iter->dpms != UTERM_DPMS_ON)
                        continue;
 
-               rb = &iter->dumb.rb[iter->dumb.current_rb];
+               ddrm = iter->data;
+               d2d = uterm_drm_display_get_data(iter);
+               rb = &d2d->rb[d2d->current_rb];
+
                memset(rb->map, 0, rb->size);
-               ret = drmModeSetCrtc(video->dumb.fd, iter->dumb.crtc_id,
-                                    rb->fb, 0, 0, &iter->dumb.conn_id, 1,
+               ret = drmModeSetCrtc(video->dumb.fd, ddrm->crtc_id,
+                                    rb->fb, 0, 0, &ddrm->conn_id, 1,
                                     uterm_drm_mode_get_info(iter->current_mode));
                if (ret) {
                        log_err("cannot set drm-crtc on display %p", iter);
@@ -524,40 +507,17 @@ static void bind_display(struct uterm_video *video, drmModeRes *res,
                                                        drmModeConnector *conn)
 {
        struct uterm_display *disp;
-       struct uterm_mode *mode;
-       int ret, i;
+       int ret;
 
        ret = display_new(&disp, &dumb_display_ops, video);
        if (ret)
                return;
 
-       for (i = 0; i < conn->count_modes; ++i) {
-               ret = mode_new(&mode, &uterm_drm_mode_ops);
-               if (ret)
-                       continue;
-               uterm_drm_mode_set(mode, &conn->modes[i]);
-               mode->next = disp->modes;
-               disp->modes = mode;
-
-               /* TODO: more sophisticated default-mode selection */
-               if (!disp->default_mode)
-                       disp->default_mode = mode;
-       }
-
-       if (!disp->modes) {
-               log_warn("no valid mode for display found");
+       ret = uterm_drm_display_bind(video, disp, res, conn, video->dumb.fd);
+       if (ret) {
                uterm_display_unref(disp);
                return;
        }
-
-       disp->dumb.conn_id = conn->connector_id;
-       disp->flags |= DISPLAY_AVAILABLE;
-       disp->next = video->displays;
-       video->displays = disp;
-       disp->dpms = uterm_drm_get_dpms(disp->video->dumb.fd, conn);
-       log_info("display %p DPMS is %s", disp,
-                       uterm_dpms_to_name(disp->dpms));
-       VIDEO_CB(video, disp, UTERM_NEW);
 }
 
 static void unbind_display(struct uterm_display *disp)
@@ -565,10 +525,7 @@ static void unbind_display(struct uterm_display *disp)
        if (!display_is_conn(disp))
                return;
 
-       VIDEO_CB(disp->video, disp, UTERM_GONE);
-       display_deactivate(disp);
-       disp->video = NULL;
-       disp->flags &= ~DISPLAY_AVAILABLE;
+       uterm_drm_display_unbind(disp);
        uterm_display_unref(disp);
 }
 
@@ -663,6 +620,7 @@ static int hotplug(struct uterm_video *video)
        drmModeRes *res;
        drmModeConnector *conn;
        struct uterm_display *disp, *tmp;
+       struct uterm_drm_display *ddrm;
        int i;
 
        if (!video_is_awake(video) || !video_need_hotplug(video))
@@ -683,7 +641,8 @@ static int hotplug(struct uterm_video *video)
                        continue;
                if (conn->connection == DRM_MODE_CONNECTED) {
                        for (disp = video->displays; disp; disp = disp->next) {
-                               if (disp->dumb.conn_id == res->connectors[i]) {
+                               ddrm = disp->data;
+                               if (ddrm->conn_id == res->connectors[i]) {
                                        disp->flags |= DISPLAY_AVAILABLE;
                                        break;
                                }
index 5c16c06..f72b12b 100644 (file)
@@ -94,24 +94,6 @@ struct uterm_video_module {
 #include <xf86drmMode.h>
 #include "static_gl.h"
 
-struct drm_rb {
-       struct uterm_display *disp;
-       struct gbm_bo *bo;
-       uint32_t fb;
-};
-
-struct drm_display {
-       uint32_t conn_id;
-       int crtc_id;
-       drmModeCrtc *saved_crtc;
-
-       struct gbm_surface *gbm;
-       EGLSurface surface;
-       struct drm_rb *current;
-       struct drm_rb *next;
-       unsigned int ignore_flips;
-};
-
 struct drm_video {
        int fd;
        struct ev_fd *efd;
@@ -140,10 +122,6 @@ struct drm_video {
 
 #else /* !BUILD_ENABLE_VIDEO_DRM */
 
-struct drm_display {
-       int unused;
-};
-
 struct drm_video {
        int unused;
 };
@@ -154,27 +132,6 @@ struct drm_video {
 
 #ifdef BUILD_ENABLE_VIDEO_DUMB
 
-#include <xf86drm.h>
-#include <xf86drmMode.h>
-
-struct dumb_rb {
-       uint32_t fb;
-       uint32_t handle;
-       uint32_t stride;
-       uint64_t size;
-
-       void *map;
-};
-
-struct dumb_display {
-       uint32_t conn_id;
-       int crtc_id;
-       drmModeCrtc *saved_crtc;
-
-       int current_rb;
-       struct dumb_rb rb[2];
-};
-
 struct dumb_video {
        int fd;
        struct ev_fd *efd;
@@ -182,10 +139,6 @@ struct dumb_video {
 
 #else /* !BUILD_ENABLE_VIDEO_DUMB */
 
-struct dumb_display {
-       int unused;
-};
-
 struct dumb_video {
        int unused;
 };
@@ -231,10 +184,6 @@ struct uterm_display {
 
        const struct display_ops *ops;
        void *data;
-       union {
-               struct drm_display drm;
-               struct dumb_display dumb;
-       };
 };
 
 int display_new(struct uterm_display **out, const struct display_ops *ops,