2016-05-02 08:45:39 -07:00
|
|
|
#include "ecore_drm2_private.h"
|
|
|
|
|
|
|
|
static Eina_Bool
|
|
|
|
_fb2_create(Ecore_Drm2_Fb *fb)
|
|
|
|
{
|
2017-03-21 12:22:40 -07:00
|
|
|
uint32_t offsets[4] = { 0 };
|
2017-03-21 12:21:14 -07:00
|
|
|
int r;
|
2016-05-02 08:45:39 -07:00
|
|
|
|
2017-03-21 12:22:40 -07:00
|
|
|
r = sym_drmModeAddFB2(fb->fd, fb->w, fb->h, fb->format, fb->handles,
|
|
|
|
fb->strides, offsets, &fb->id, 0);
|
2017-03-21 12:21:14 -07:00
|
|
|
|
|
|
|
if (r)
|
|
|
|
return EINA_FALSE;
|
2016-05-02 08:45:39 -07:00
|
|
|
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Ecore_Drm2_Fb *
|
|
|
|
ecore_drm2_fb_create(int fd, int width, int height, int depth, int bpp, unsigned int format)
|
|
|
|
{
|
|
|
|
Ecore_Drm2_Fb *fb;
|
2016-11-14 10:35:38 -08:00
|
|
|
drm_mode_create_dumb carg;
|
|
|
|
drm_mode_destroy_dumb darg;
|
|
|
|
drm_mode_map_dumb marg;
|
2016-05-02 08:45:39 -07:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_TRUE_RETURN_VAL((fd < 0), NULL);
|
|
|
|
|
|
|
|
fb = calloc(1, sizeof(Ecore_Drm2_Fb));
|
|
|
|
if (!fb) return NULL;
|
|
|
|
|
|
|
|
fb->fd = fd;
|
|
|
|
fb->w = width;
|
|
|
|
fb->h = height;
|
|
|
|
fb->bpp = bpp;
|
|
|
|
fb->depth = depth;
|
|
|
|
fb->format = format;
|
|
|
|
|
2016-11-14 10:35:38 -08:00
|
|
|
memset(&carg, 0, sizeof(drm_mode_create_dumb));
|
2016-05-02 08:45:39 -07:00
|
|
|
carg.bpp = bpp;
|
|
|
|
carg.width = width;
|
|
|
|
carg.height = height;
|
|
|
|
|
2016-11-14 10:35:38 -08:00
|
|
|
ret = sym_drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &carg);
|
2016-05-02 08:45:39 -07:00
|
|
|
if (ret) goto err;
|
|
|
|
|
2017-03-21 12:22:40 -07:00
|
|
|
fb->handles[0] = carg.handle;
|
|
|
|
fb->sizes[0] = carg.size;
|
|
|
|
fb->strides[0] = carg.pitch;
|
2016-05-02 08:45:39 -07:00
|
|
|
|
|
|
|
if (!_fb2_create(fb))
|
|
|
|
{
|
|
|
|
ret =
|
2016-11-14 10:35:38 -08:00
|
|
|
sym_drmModeAddFB(fd, width, height, depth, bpp,
|
2017-03-21 12:22:40 -07:00
|
|
|
fb->strides[0], fb->handles[0], &fb->id);
|
2016-05-02 08:45:39 -07:00
|
|
|
if (ret)
|
|
|
|
{
|
|
|
|
ERR("Could not add framebuffer: %m");
|
|
|
|
goto add_err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-14 10:35:38 -08:00
|
|
|
memset(&marg, 0, sizeof(drm_mode_map_dumb));
|
2017-03-21 12:22:40 -07:00
|
|
|
marg.handle = fb->handles[0];
|
2016-11-14 10:35:38 -08:00
|
|
|
ret = sym_drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &marg);
|
2016-05-02 08:45:39 -07:00
|
|
|
if (ret)
|
|
|
|
{
|
|
|
|
ERR("Could not map framebuffer: %m");
|
|
|
|
goto map_err;
|
|
|
|
}
|
|
|
|
|
2017-03-21 12:22:40 -07:00
|
|
|
fb->mmap = mmap(NULL, fb->sizes[0], PROT_WRITE, MAP_SHARED, fd, marg.offset);
|
2016-05-02 08:45:39 -07:00
|
|
|
if (fb->mmap == MAP_FAILED)
|
|
|
|
{
|
|
|
|
ERR("Could not mmap framebuffer memory: %m");
|
|
|
|
goto map_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return fb;
|
|
|
|
|
|
|
|
map_err:
|
2016-11-14 10:35:38 -08:00
|
|
|
sym_drmModeRmFB(fd, fb->id);
|
2016-05-02 08:45:39 -07:00
|
|
|
add_err:
|
2016-11-14 10:35:38 -08:00
|
|
|
memset(&darg, 0, sizeof(drm_mode_destroy_dumb));
|
2017-03-21 12:22:40 -07:00
|
|
|
darg.handle = fb->handles[0];
|
2016-11-14 10:35:38 -08:00
|
|
|
sym_drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &darg);
|
2016-05-02 08:45:39 -07:00
|
|
|
err:
|
|
|
|
free(fb);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Ecore_Drm2_Fb *
|
2016-09-09 11:18:41 -07:00
|
|
|
ecore_drm2_fb_gbm_create(int fd, int width, int height, int depth, int bpp, unsigned int format, unsigned int handle, unsigned int stride, void *bo)
|
2016-05-02 08:45:39 -07:00
|
|
|
{
|
2016-11-14 10:35:38 -08:00
|
|
|
drm_mode_map_dumb marg;
|
2016-05-02 08:45:39 -07:00
|
|
|
Ecore_Drm2_Fb *fb;
|
2016-07-14 14:25:05 -07:00
|
|
|
int ret;
|
2016-05-02 08:45:39 -07:00
|
|
|
|
|
|
|
EINA_SAFETY_ON_TRUE_RETURN_VAL((fd < 0), NULL);
|
|
|
|
|
|
|
|
fb = calloc(1, sizeof(Ecore_Drm2_Fb));
|
|
|
|
if (!fb) return NULL;
|
|
|
|
|
|
|
|
fb->gbm = EINA_TRUE;
|
2016-09-09 11:18:41 -07:00
|
|
|
fb->gbm_bo = bo;
|
2016-05-02 08:45:39 -07:00
|
|
|
|
|
|
|
fb->fd = fd;
|
|
|
|
fb->w = width;
|
|
|
|
fb->h = height;
|
|
|
|
fb->bpp = bpp;
|
|
|
|
fb->depth = depth;
|
|
|
|
fb->format = format;
|
2017-03-21 12:22:40 -07:00
|
|
|
fb->strides[0] = stride;
|
|
|
|
fb->sizes[0] = fb->strides[0] * fb->h;
|
|
|
|
fb->handles[0] = handle;
|
2016-05-02 08:45:39 -07:00
|
|
|
|
|
|
|
if (!_fb2_create(fb))
|
|
|
|
{
|
2016-11-14 10:35:38 -08:00
|
|
|
if (sym_drmModeAddFB(fd, width, height, depth, bpp,
|
2017-03-21 12:22:40 -07:00
|
|
|
fb->strides[0], fb->handles[0], &fb->id))
|
2016-05-02 08:45:39 -07:00
|
|
|
{
|
|
|
|
ERR("Could not add framebuffer: %m");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-14 14:25:05 -07:00
|
|
|
/* mmap it if we can so screenshots are easy */
|
2016-11-14 10:35:38 -08:00
|
|
|
memset(&marg, 0, sizeof(drm_mode_map_dumb));
|
2017-03-21 12:22:40 -07:00
|
|
|
marg.handle = fb->handles[0];
|
2016-11-14 10:35:38 -08:00
|
|
|
ret = sym_drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &marg);
|
2016-07-14 14:25:05 -07:00
|
|
|
if (!ret)
|
|
|
|
{
|
2017-03-21 12:22:40 -07:00
|
|
|
fb->mmap = mmap(NULL, fb->sizes[0], PROT_WRITE, MAP_SHARED, fd, marg.offset);
|
2016-07-14 14:25:05 -07:00
|
|
|
if (fb->mmap == MAP_FAILED) fb->mmap = NULL;
|
|
|
|
}
|
2016-05-02 08:45:39 -07:00
|
|
|
return fb;
|
|
|
|
|
|
|
|
err:
|
|
|
|
free(fb);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
|
|
|
ecore_drm2_fb_destroy(Ecore_Drm2_Fb *fb)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN(fb);
|
|
|
|
|
2017-03-21 12:22:40 -07:00
|
|
|
if (fb->mmap) munmap(fb->mmap, fb->sizes[0]);
|
2016-07-14 14:25:05 -07:00
|
|
|
|
2016-11-14 10:35:38 -08:00
|
|
|
if (fb->id) sym_drmModeRmFB(fb->fd, fb->id);
|
2016-05-02 08:45:39 -07:00
|
|
|
|
|
|
|
if (!fb->gbm)
|
|
|
|
{
|
2016-11-14 10:35:38 -08:00
|
|
|
drm_mode_destroy_dumb darg;
|
2016-05-02 08:45:39 -07:00
|
|
|
|
2016-11-14 10:35:38 -08:00
|
|
|
memset(&darg, 0, sizeof(drm_mode_destroy_dumb));
|
2017-03-21 12:22:40 -07:00
|
|
|
darg.handle = fb->handles[0];
|
2016-11-14 10:35:38 -08:00
|
|
|
sym_drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &darg);
|
2016-05-02 08:45:39 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
free(fb);
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void *
|
|
|
|
ecore_drm2_fb_data_get(Ecore_Drm2_Fb *fb)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(fb, NULL);
|
|
|
|
return fb->mmap;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI unsigned int
|
|
|
|
ecore_drm2_fb_size_get(Ecore_Drm2_Fb *fb)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(fb, 0);
|
2017-03-21 12:22:40 -07:00
|
|
|
return fb->sizes[0];
|
2016-05-02 08:45:39 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI unsigned int
|
|
|
|
ecore_drm2_fb_stride_get(Ecore_Drm2_Fb *fb)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(fb, 0);
|
2017-03-21 12:22:40 -07:00
|
|
|
return fb->strides[0];
|
2016-05-02 08:45:39 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
|
|
|
ecore_drm2_fb_dirty(Ecore_Drm2_Fb *fb, Eina_Rectangle *rects, unsigned int count)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN(fb);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN(rects);
|
|
|
|
|
|
|
|
#ifdef DRM_MODE_FEATURE_DIRTYFB
|
|
|
|
drmModeClip *clip;
|
|
|
|
unsigned int i = 0;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
clip = alloca(count * sizeof(drmModeClip));
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
clip[i].x1 = rects[i].x;
|
|
|
|
clip[i].y1 = rects[i].y;
|
|
|
|
clip[i].x2 = rects[i].w;
|
|
|
|
clip[i].y2 = rects[i].h;
|
|
|
|
}
|
|
|
|
|
2016-11-14 10:35:38 -08:00
|
|
|
ret = sym_drmModeDirtyFB(fb->fd, fb->id, clip, count);
|
2016-05-02 08:45:39 -07:00
|
|
|
if ((ret) && (ret == -EINVAL))
|
|
|
|
WRN("Could not mark framebuffer as dirty: %m");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2016-09-09 12:05:00 -07:00
|
|
|
static void
|
2017-04-28 10:22:04 -07:00
|
|
|
_release_buffer(Ecore_Drm2_Output *output, Ecore_Drm2_Output_State *s)
|
2016-09-09 11:31:20 -07:00
|
|
|
{
|
2017-04-28 10:22:04 -07:00
|
|
|
s->fb->busy = EINA_FALSE;
|
|
|
|
if (output->release_cb) output->release_cb(output->release_data, s->fb);
|
|
|
|
s->fb = NULL;
|
2016-09-09 11:31:20 -07:00
|
|
|
}
|
|
|
|
|
2016-09-07 20:24:45 -07:00
|
|
|
EAPI Eina_Bool
|
|
|
|
ecore_drm2_fb_flip_complete(Ecore_Drm2_Output *output)
|
|
|
|
{
|
2016-09-09 12:05:00 -07:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE);
|
|
|
|
|
2017-04-27 14:43:06 -07:00
|
|
|
if (output->current.fb && (output->current.fb != output->pending.fb))
|
2017-04-28 10:22:04 -07:00
|
|
|
_release_buffer(output, &output->current);
|
2017-04-27 14:43:06 -07:00
|
|
|
output->current.fb = output->pending.fb;
|
|
|
|
output->pending.fb = NULL;
|
2016-09-07 20:24:45 -07:00
|
|
|
|
2017-04-27 14:43:06 -07:00
|
|
|
return !!output->next.fb;
|
2016-09-07 20:24:45 -07:00
|
|
|
}
|
|
|
|
|
2017-04-27 13:50:38 -07:00
|
|
|
Eina_Bool
|
2017-04-27 06:11:41 -07:00
|
|
|
_fb_atomic_flip_test(Ecore_Drm2_Output *output)
|
2016-05-02 08:45:39 -07:00
|
|
|
{
|
2017-04-27 06:11:41 -07:00
|
|
|
Eina_Bool res = EINA_FALSE;
|
|
|
|
#ifdef HAVE_ATOMIC_DRM
|
2016-05-02 08:45:39 -07:00
|
|
|
int ret = 0;
|
2017-04-27 06:11:41 -07:00
|
|
|
Eina_List *l;
|
|
|
|
Ecore_Drm2_Crtc_State *cstate;
|
|
|
|
Ecore_Drm2_Plane_State *pstate;
|
|
|
|
Ecore_Drm2_Plane *plane;
|
|
|
|
drmModeAtomicReq *req = NULL;
|
|
|
|
uint32_t flags = DRM_MODE_ATOMIC_NONBLOCK | DRM_MODE_ATOMIC_ALLOW_MODESET |
|
|
|
|
DRM_MODE_ATOMIC_TEST_ONLY;
|
2016-05-02 08:45:39 -07:00
|
|
|
|
2017-04-27 06:11:41 -07:00
|
|
|
req = sym_drmModeAtomicAlloc();
|
|
|
|
if (!req) return EINA_FALSE;
|
2016-05-02 08:45:39 -07:00
|
|
|
|
2017-04-27 06:11:41 -07:00
|
|
|
sym_drmModeAtomicSetCursor(req, 0);
|
|
|
|
|
|
|
|
cstate = output->crtc_state;
|
|
|
|
|
|
|
|
ret =
|
|
|
|
sym_drmModeAtomicAddProperty(req, cstate->obj_id, cstate->mode.id,
|
|
|
|
cstate->mode.value);
|
|
|
|
if (ret < 0) goto err;
|
|
|
|
|
|
|
|
ret =
|
|
|
|
sym_drmModeAtomicAddProperty(req, cstate->obj_id, cstate->active.id,
|
|
|
|
cstate->active.value);
|
|
|
|
if (ret < 0) goto err;
|
|
|
|
|
|
|
|
EINA_LIST_FOREACH(output->planes, l, plane)
|
|
|
|
{
|
|
|
|
pstate = plane->state;
|
|
|
|
|
|
|
|
ret =
|
|
|
|
sym_drmModeAtomicAddProperty(req, pstate->obj_id,
|
|
|
|
pstate->cid.id, pstate->cid.value);
|
|
|
|
if (ret < 0) goto err;
|
|
|
|
|
|
|
|
ret =
|
|
|
|
sym_drmModeAtomicAddProperty(req, pstate->obj_id,
|
|
|
|
pstate->fid.id, pstate->fid.value);
|
|
|
|
if (ret < 0) goto err;
|
|
|
|
|
|
|
|
ret =
|
|
|
|
sym_drmModeAtomicAddProperty(req, pstate->obj_id,
|
|
|
|
pstate->sx.id, pstate->sx.value);
|
|
|
|
if (ret < 0) goto err;
|
|
|
|
|
|
|
|
ret =
|
|
|
|
sym_drmModeAtomicAddProperty(req, pstate->obj_id,
|
|
|
|
pstate->sy.id, pstate->sy.value);
|
|
|
|
if (ret < 0) goto err;
|
|
|
|
|
|
|
|
ret =
|
|
|
|
sym_drmModeAtomicAddProperty(req, pstate->obj_id,
|
|
|
|
pstate->sw.id, pstate->sw.value);
|
|
|
|
if (ret < 0) goto err;
|
|
|
|
|
|
|
|
ret =
|
|
|
|
sym_drmModeAtomicAddProperty(req, pstate->obj_id,
|
|
|
|
pstate->sh.id, pstate->sh.value);
|
|
|
|
if (ret < 0) goto err;
|
|
|
|
|
|
|
|
ret =
|
|
|
|
sym_drmModeAtomicAddProperty(req, pstate->obj_id,
|
|
|
|
pstate->cx.id, pstate->cx.value);
|
|
|
|
if (ret < 0) goto err;
|
|
|
|
|
|
|
|
ret =
|
|
|
|
sym_drmModeAtomicAddProperty(req, pstate->obj_id,
|
|
|
|
pstate->cy.id, pstate->cy.value);
|
|
|
|
if (ret < 0) goto err;
|
|
|
|
|
|
|
|
ret =
|
|
|
|
sym_drmModeAtomicAddProperty(req, pstate->obj_id,
|
|
|
|
pstate->cw.id, pstate->cw.value);
|
|
|
|
if (ret < 0) goto err;
|
|
|
|
|
|
|
|
ret =
|
|
|
|
sym_drmModeAtomicAddProperty(req, pstate->obj_id,
|
|
|
|
pstate->ch.id, pstate->ch.value);
|
|
|
|
if (ret < 0) goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret =
|
|
|
|
sym_drmModeAtomicCommit(output->fd, req, flags, NULL);
|
|
|
|
if (ret < 0) ERR("Failed Atomic Commit Test: %m");
|
|
|
|
else res = EINA_TRUE;
|
|
|
|
|
|
|
|
if (res)
|
|
|
|
{
|
2017-04-27 14:02:59 -07:00
|
|
|
if (output->prep.atomic_req)
|
2017-04-27 06:11:41 -07:00
|
|
|
{
|
2017-04-27 13:34:52 -07:00
|
|
|
/* clear any previous request */
|
2017-04-27 14:02:59 -07:00
|
|
|
sym_drmModeAtomicFree(output->prep.atomic_req);
|
2017-04-27 13:34:52 -07:00
|
|
|
|
|
|
|
/* just use the new request */
|
2017-04-27 14:02:59 -07:00
|
|
|
output->prep.atomic_req = req;
|
2017-04-27 06:11:41 -07:00
|
|
|
}
|
|
|
|
else
|
2017-04-27 14:02:59 -07:00
|
|
|
output->prep.atomic_req = req;
|
2017-04-27 06:11:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
|
|
|
err:
|
|
|
|
sym_drmModeAtomicFree(req);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
_fb_atomic_flip(Ecore_Drm2_Output *output)
|
|
|
|
{
|
|
|
|
#ifdef HAVE_ATOMIC_DRM
|
|
|
|
int res = 0;
|
|
|
|
uint32_t flags =
|
|
|
|
DRM_MODE_ATOMIC_NONBLOCK | DRM_MODE_PAGE_FLIP_EVENT |
|
|
|
|
DRM_MODE_ATOMIC_ALLOW_MODESET;
|
|
|
|
|
2017-04-28 08:38:30 -07:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(output->prep.atomic_req, -1);
|
2017-04-27 06:11:41 -07:00
|
|
|
|
|
|
|
res =
|
2017-04-27 14:02:59 -07:00
|
|
|
sym_drmModeAtomicCommit(output->fd,
|
|
|
|
output->prep.atomic_req, flags, NULL);
|
2017-04-27 06:11:41 -07:00
|
|
|
if (res < 0)
|
|
|
|
{
|
2017-04-27 08:13:46 -07:00
|
|
|
ERR("Failed Atomic Commit: %m");
|
2017-04-27 06:11:41 -07:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2017-04-27 14:52:09 -07:00
|
|
|
_fb_flip(Ecore_Drm2_Output *output)
|
2017-04-27 06:11:41 -07:00
|
|
|
{
|
2017-04-27 14:52:09 -07:00
|
|
|
Ecore_Drm2_Fb *fb;
|
2017-04-27 06:11:41 -07:00
|
|
|
Eina_Bool repeat;
|
|
|
|
int count = 0;
|
|
|
|
int ret = 0;
|
2016-06-21 09:55:17 -07:00
|
|
|
|
2017-04-27 14:52:09 -07:00
|
|
|
fb = output->prep.fb;
|
|
|
|
|
2017-04-27 14:43:06 -07:00
|
|
|
if ((!output->current.fb) ||
|
|
|
|
(output->current.fb->strides[0] != fb->strides[0]))
|
2016-05-02 08:45:39 -07:00
|
|
|
{
|
2017-03-27 06:27:19 -07:00
|
|
|
ret =
|
|
|
|
sym_drmModeSetCrtc(fb->fd, output->crtc_id, fb->id,
|
|
|
|
output->x, output->y, &output->conn_id, 1,
|
|
|
|
&output->current_mode->info);
|
|
|
|
if (ret)
|
2016-05-02 08:45:39 -07:00
|
|
|
{
|
2017-03-27 06:27:19 -07:00
|
|
|
ERR("Failed to set Mode %dx%d for Output %s: %m",
|
|
|
|
output->current_mode->width, output->current_mode->height,
|
|
|
|
output->name);
|
2016-05-02 08:45:39 -07:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-04-28 10:22:04 -07:00
|
|
|
if (output->current.fb) _release_buffer(output, &output->current);
|
2017-04-27 14:43:06 -07:00
|
|
|
output->current.fb = fb;
|
|
|
|
output->current.fb->busy = EINA_TRUE;
|
|
|
|
output->next.fb = NULL;
|
2017-03-27 06:27:19 -07:00
|
|
|
/* We used to return here, but now that the ticker is fixed this
|
|
|
|
* can leave us hanging waiting for a tick to happen forever.
|
2017-04-28 09:26:08 -07:00
|
|
|
* Instead, we now fall through to the flip path to make sure
|
2017-03-27 06:27:19 -07:00
|
|
|
* even this first set can cause a flip callback.
|
|
|
|
*/
|
2016-05-02 08:45:39 -07:00
|
|
|
}
|
2017-01-06 20:16:06 -08:00
|
|
|
|
2017-03-27 06:27:19 -07:00
|
|
|
do
|
|
|
|
{
|
|
|
|
static Eina_Bool bugged_about_bug = EINA_FALSE;
|
|
|
|
repeat = EINA_FALSE;
|
|
|
|
ret = sym_drmModePageFlip(fb->fd, output->crtc_id, fb->id,
|
|
|
|
DRM_MODE_PAGE_FLIP_EVENT,
|
|
|
|
output->user_data);
|
|
|
|
/* Some drivers (RPI - looking at you) are broken and produce
|
|
|
|
* flip events before they are ready for another flip, so be
|
|
|
|
* a little robust in the face of badness and try a few times
|
|
|
|
* until we can flip or we give up (100 tries with a yield
|
|
|
|
* between each try). We can't expect everyone to run the
|
|
|
|
* latest bleeding edge kernel IF a workaround is possible
|
|
|
|
* in userspace, so do this.
|
|
|
|
* We only report this as an ERR once since if it will
|
|
|
|
* generate a huge amount of spam otherwise. */
|
|
|
|
if ((ret < 0) && (errno == EBUSY))
|
2016-09-22 10:30:49 -07:00
|
|
|
{
|
2017-03-27 06:27:19 -07:00
|
|
|
repeat = EINA_TRUE;
|
|
|
|
if (count == 0 && !bugged_about_bug)
|
2016-09-22 10:30:49 -07:00
|
|
|
{
|
2017-03-27 06:27:19 -07:00
|
|
|
ERR("Pageflip fail - EBUSY from drmModePageFlip - "
|
|
|
|
"This is either a kernel bug or an EFL one.");
|
|
|
|
bugged_about_bug = EINA_TRUE;
|
2016-09-22 10:30:49 -07:00
|
|
|
}
|
2017-03-27 06:27:19 -07:00
|
|
|
count++;
|
|
|
|
if (count > 500)
|
2017-01-06 20:16:06 -08:00
|
|
|
{
|
2017-03-27 06:27:19 -07:00
|
|
|
ERR("Pageflip EBUSY for %i tries - give up", count);
|
|
|
|
break;
|
2017-01-06 20:16:06 -08:00
|
|
|
}
|
2017-03-27 06:27:19 -07:00
|
|
|
usleep(100);
|
2017-01-06 20:16:06 -08:00
|
|
|
}
|
2017-03-27 06:27:19 -07:00
|
|
|
}
|
|
|
|
while (repeat);
|
2017-01-06 20:16:06 -08:00
|
|
|
|
2017-03-27 06:27:19 -07:00
|
|
|
if ((ret == 0) && (count > 0))
|
|
|
|
DBG("Pageflip finally succeeded after %i tries due to EBUSY", count);
|
2016-09-22 10:30:49 -07:00
|
|
|
|
2017-03-27 06:27:19 -07:00
|
|
|
if ((ret < 0) && (errno != EBUSY))
|
|
|
|
{
|
|
|
|
ERR("Pageflip Failed for Crtc %u on Connector %u: %m",
|
|
|
|
output->crtc_id, output->conn_id);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
else if (ret < 0)
|
|
|
|
{
|
2017-04-27 14:43:06 -07:00
|
|
|
output->next.fb = fb;
|
|
|
|
output->next.fb->busy = EINA_TRUE;
|
2016-09-07 20:16:10 -07:00
|
|
|
return 0;
|
|
|
|
}
|
2017-03-27 06:27:19 -07:00
|
|
|
|
|
|
|
return 0;
|
2016-05-02 08:45:39 -07:00
|
|
|
}
|
2016-09-02 10:17:01 -07:00
|
|
|
|
2017-04-27 06:11:41 -07:00
|
|
|
EAPI int
|
|
|
|
ecore_drm2_fb_flip(Ecore_Drm2_Fb *fb, Ecore_Drm2_Output *output)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(output, -1);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(output->current_mode, -1);
|
|
|
|
|
|
|
|
if (!output->enabled) return -1;
|
|
|
|
|
2017-04-28 09:27:10 -07:00
|
|
|
if (output->pending.fb)
|
|
|
|
{
|
2017-04-28 10:22:04 -07:00
|
|
|
if (output->next.fb) _release_buffer(output, &output->next);
|
2017-04-28 09:27:10 -07:00
|
|
|
output->next.fb = fb;
|
|
|
|
if (output->next.fb) output->next.fb->busy = EINA_TRUE;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (!fb) fb = output->next.fb;
|
|
|
|
|
|
|
|
/* So we can generate a tick by flipping to the current fb */
|
|
|
|
if (!fb) fb = output->current.fb;
|
|
|
|
|
|
|
|
if (output->next.fb)
|
|
|
|
{
|
|
|
|
output->next.fb->busy = EINA_FALSE;
|
|
|
|
output->next.fb = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we don't have an fb to set by now, BAIL! */
|
|
|
|
if (!fb) return -1;
|
|
|
|
|
2017-04-27 14:52:09 -07:00
|
|
|
output->prep.fb = fb;
|
|
|
|
|
2017-04-27 06:11:41 -07:00
|
|
|
if (_ecore_drm2_use_atomic)
|
|
|
|
ret = _fb_atomic_flip(output);
|
|
|
|
else
|
2017-04-27 14:52:09 -07:00
|
|
|
ret = _fb_flip(output);
|
2017-04-27 06:11:41 -07:00
|
|
|
|
2017-04-28 09:27:10 -07:00
|
|
|
output->pending.fb = fb;
|
|
|
|
output->pending.fb->busy = EINA_TRUE;
|
|
|
|
output->prep.fb = NULL;
|
|
|
|
|
2017-04-27 06:11:41 -07:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-09-02 10:17:01 -07:00
|
|
|
EAPI Eina_Bool
|
|
|
|
ecore_drm2_fb_busy_get(Ecore_Drm2_Fb *fb)
|
|
|
|
{
|
2016-09-09 12:05:00 -07:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(fb, EINA_FALSE);
|
2016-09-02 10:17:01 -07:00
|
|
|
return fb->busy;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
|
|
|
ecore_drm2_fb_busy_set(Ecore_Drm2_Fb *fb, Eina_Bool busy)
|
|
|
|
{
|
2016-09-09 12:05:00 -07:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN(fb);
|
2016-09-02 10:17:01 -07:00
|
|
|
fb->busy = busy;
|
|
|
|
}
|
2016-09-09 11:18:41 -07:00
|
|
|
|
2016-12-07 09:28:33 -08:00
|
|
|
EAPI Eina_Bool
|
2016-11-18 07:41:52 -08:00
|
|
|
ecore_drm2_fb_release(Ecore_Drm2_Output *o, Eina_Bool panic)
|
2016-09-09 11:33:15 -07:00
|
|
|
{
|
2016-12-07 09:28:33 -08:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(o, EINA_FALSE);
|
2016-09-09 12:05:00 -07:00
|
|
|
|
2017-04-27 14:43:06 -07:00
|
|
|
if (o->next.fb)
|
2016-09-09 11:33:15 -07:00
|
|
|
{
|
2017-04-28 10:22:04 -07:00
|
|
|
_release_buffer(o, &o->next);
|
2016-12-07 09:28:33 -08:00
|
|
|
return EINA_TRUE;
|
2016-09-09 11:33:15 -07:00
|
|
|
}
|
2016-12-07 09:28:33 -08:00
|
|
|
if (!panic) return EINA_FALSE;
|
2016-09-09 11:33:15 -07:00
|
|
|
|
2016-12-07 09:28:33 -08:00
|
|
|
/* This has been demoted to DBG from WRN because we
|
|
|
|
* call this function to reclaim all buffers on a
|
|
|
|
* surface resize.
|
|
|
|
*/
|
|
|
|
DBG("Buffer release request when no next buffer");
|
2016-09-09 11:33:15 -07:00
|
|
|
/* If we have to release these we're going to see tearing.
|
|
|
|
* Try to reclaim in decreasing order of visual awfulness
|
|
|
|
*/
|
2017-04-27 14:43:06 -07:00
|
|
|
if (o->current.fb)
|
2016-09-09 11:33:15 -07:00
|
|
|
{
|
2017-04-28 10:22:04 -07:00
|
|
|
_release_buffer(o, &o->current);
|
2016-12-07 09:28:33 -08:00
|
|
|
return EINA_TRUE;
|
2016-09-09 11:33:15 -07:00
|
|
|
}
|
|
|
|
|
2017-04-27 14:43:06 -07:00
|
|
|
if (o->pending.fb)
|
2016-09-09 11:33:15 -07:00
|
|
|
{
|
2017-04-28 10:22:04 -07:00
|
|
|
_release_buffer(o, &o->pending);
|
2016-12-07 09:28:33 -08:00
|
|
|
return EINA_TRUE;
|
2016-09-09 11:33:15 -07:00
|
|
|
}
|
2016-12-07 09:28:33 -08:00
|
|
|
|
|
|
|
return EINA_FALSE;
|
2016-09-09 11:33:15 -07:00
|
|
|
}
|
|
|
|
|
2016-09-09 11:18:41 -07:00
|
|
|
EAPI void *
|
2016-09-09 12:05:00 -07:00
|
|
|
ecore_drm2_fb_bo_get(Ecore_Drm2_Fb *fb)
|
2016-09-09 11:18:41 -07:00
|
|
|
{
|
2016-09-09 12:05:00 -07:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(fb, NULL);
|
|
|
|
return fb->gbm_bo;
|
2016-09-09 11:18:41 -07:00
|
|
|
}
|
2017-03-21 13:44:46 -07:00
|
|
|
|
|
|
|
EAPI Ecore_Drm2_Fb *
|
|
|
|
ecore_drm2_fb_dmabuf_import(int fd, int width, int height, int depth, int bpp, unsigned int format, unsigned int strides[4], int dmabuf_fd[4], int dmabuf_fd_count)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
Ecore_Drm2_Fb *fb;
|
|
|
|
|
|
|
|
fb = calloc(1, sizeof(Ecore_Drm2_Fb));
|
|
|
|
if (!fb) return NULL;
|
|
|
|
|
|
|
|
for (i = 0; i < dmabuf_fd_count; i++)
|
2017-04-25 07:27:37 -07:00
|
|
|
if (sym_drmPrimeFDToHandle(fd, dmabuf_fd[i], &fb->handles[i]))
|
|
|
|
goto fail;
|
2017-03-21 13:44:46 -07:00
|
|
|
|
|
|
|
fb->fd = fd;
|
|
|
|
fb->w = width;
|
|
|
|
fb->h = height;
|
|
|
|
fb->bpp = bpp;
|
|
|
|
fb->depth = depth;
|
|
|
|
fb->format = format;
|
|
|
|
memcpy(&fb->strides, strides, sizeof(fb->strides));
|
|
|
|
if (_fb2_create(fb)) return fb;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
free(fb);
|
|
|
|
return NULL;
|
|
|
|
}
|