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;
+}
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 */
#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;
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;;
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;
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;
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;
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;
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;
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;
}
{
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
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;
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;
}
}
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,
}
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)
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);
}
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);
}
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))
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;
}
#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;
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;
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)
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;
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;
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;
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;
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;
{
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;
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);
{
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);
{
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);
}
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,
{
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;
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);
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)
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);
}
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))
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;
}
#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;
#else /* !BUILD_ENABLE_VIDEO_DRM */
-struct drm_display {
- int unused;
-};
-
struct drm_video {
int unused;
};
#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;
#else /* !BUILD_ENABLE_VIDEO_DUMB */
-struct dumb_display {
- int unused;
-};
-
struct dumb_video {
int unused;
};
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,