2014-03-06 01:43:48 -08:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include <config.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "ecore_drm_private.h"
|
|
|
|
|
|
|
|
/**
|
2014-03-15 04:03:08 -07:00
|
|
|
* @defgroup Ecore_Drm_Fb_Group Frame buffer manipulation
|
|
|
|
*
|
|
|
|
* Functions that deal with frame buffers.
|
|
|
|
*
|
2014-03-06 01:43:48 -08:00
|
|
|
*/
|
|
|
|
|
2015-04-07 07:23:41 -07:00
|
|
|
static Eina_Bool
|
2015-04-07 07:49:45 -07:00
|
|
|
_ecore_drm_fb_create2(int fd, Ecore_Drm_Fb *fb)
|
2015-04-07 07:23:41 -07:00
|
|
|
{
|
|
|
|
struct drm_mode_fb_cmd2 cmd;
|
|
|
|
uint32_t hdls[4], pitches[4], offsets[4], fmt;
|
|
|
|
|
|
|
|
#define _fourcc_code(a,b,c,d) \
|
|
|
|
((uint32_t)(a) | ((uint32_t)(b) << 8) | \
|
|
|
|
((uint32_t)(c) << 16) | ((uint32_t)(d) << 24))
|
|
|
|
fmt = (_fourcc_code('X', 'R', '2', '4'));
|
|
|
|
|
|
|
|
hdls[0] = fb->hdl;
|
|
|
|
pitches[0] = fb->stride;
|
|
|
|
offsets[0] = 0;
|
|
|
|
|
|
|
|
memset(&cmd, 0, sizeof(struct drm_mode_fb_cmd2));
|
|
|
|
cmd.fb_id = 0;
|
2015-04-07 07:49:45 -07:00
|
|
|
cmd.width = fb->w;
|
|
|
|
cmd.height = fb->h;
|
2015-04-07 07:23:41 -07:00
|
|
|
cmd.pixel_format = fmt;
|
|
|
|
cmd.flags = 0;
|
|
|
|
memcpy(cmd.handles, hdls, 4 * sizeof(hdls[0]));
|
|
|
|
memcpy(cmd.pitches, pitches, 4 * sizeof(pitches[0]));
|
|
|
|
memcpy(cmd.offsets, offsets, 4 * sizeof(offsets[0]));
|
|
|
|
|
|
|
|
if (drmIoctl(fd, DRM_IOCTL_MODE_ADDFB2, &cmd))
|
|
|
|
return EINA_FALSE;
|
|
|
|
|
|
|
|
fb->id = cmd.fb_id;
|
|
|
|
|
|
|
|
/* if (drmModeAddFB2(fd, w, h, fmt, hdls, pitches, offsets, &fb->id, 0)) */
|
|
|
|
/* return EINA_FALSE; */
|
|
|
|
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
2014-03-06 01:43:48 -08:00
|
|
|
EAPI Ecore_Drm_Fb *
|
|
|
|
ecore_drm_fb_create(Ecore_Drm_Device *dev, int width, int height)
|
|
|
|
{
|
|
|
|
Ecore_Drm_Fb *fb;
|
|
|
|
struct drm_mode_create_dumb carg;
|
|
|
|
struct drm_mode_destroy_dumb darg;
|
|
|
|
struct drm_mode_map_dumb marg;
|
|
|
|
|
2015-04-24 09:51:34 -07:00
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(dev, NULL);
|
|
|
|
EINA_SAFETY_ON_TRUE_RETURN_VAL((width < 1) || (height < 1), NULL);
|
2014-03-06 01:43:48 -08:00
|
|
|
if (!(fb = calloc(1, sizeof(Ecore_Drm_Fb)))) return NULL;
|
|
|
|
|
|
|
|
memset(&carg, 0, sizeof(struct drm_mode_create_dumb));
|
|
|
|
|
|
|
|
carg.bpp = 32; // FIXME: Hard-coded depth
|
|
|
|
carg.width = width;
|
|
|
|
carg.height = height;
|
|
|
|
|
|
|
|
if (drmIoctl(dev->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &carg))
|
|
|
|
{
|
|
|
|
ERR("Could not create dumb framebuffer: %m");
|
|
|
|
goto create_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
fb->from_client = EINA_TRUE;
|
|
|
|
fb->hdl = carg.handle;
|
|
|
|
fb->stride = carg.pitch;
|
|
|
|
fb->size = carg.size;
|
|
|
|
fb->fd = dev->drm.fd;
|
2015-04-07 07:49:45 -07:00
|
|
|
fb->w = width;
|
|
|
|
fb->h = height;
|
2014-03-06 01:43:48 -08:00
|
|
|
|
2015-04-07 07:49:45 -07:00
|
|
|
if (!_ecore_drm_fb_create2(dev->drm.fd, fb))
|
2014-03-06 01:43:48 -08:00
|
|
|
{
|
2015-04-07 07:23:41 -07:00
|
|
|
WRN("Could not add framebuffer2: %m");
|
2015-04-07 07:49:45 -07:00
|
|
|
if (drmModeAddFB(dev->drm.fd, fb->w, fb->h, 24, 32,
|
2015-04-07 07:23:41 -07:00
|
|
|
fb->stride, fb->hdl, &fb->id))
|
|
|
|
{
|
|
|
|
ERR("Could not add framebuffer: %m");
|
|
|
|
goto add_err;
|
|
|
|
}
|
2014-03-06 01:43:48 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
memset(&marg, 0, sizeof(struct drm_mode_map_dumb));
|
|
|
|
marg.handle = fb->hdl;
|
|
|
|
if (drmIoctl(dev->drm.fd, DRM_IOCTL_MODE_MAP_DUMB, &marg))
|
|
|
|
{
|
|
|
|
ERR("Could not map framebuffer: %m");
|
|
|
|
goto map_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
fb->mmap =
|
|
|
|
mmap(0, fb->size, PROT_WRITE | PROT_READ, MAP_SHARED,
|
|
|
|
dev->drm.fd, marg.offset);
|
|
|
|
if (fb->mmap == MAP_FAILED)
|
|
|
|
{
|
|
|
|
ERR("Could not mmap framebuffer space: %m");
|
|
|
|
goto map_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(fb->mmap, 0, fb->size);
|
|
|
|
|
|
|
|
return fb;
|
|
|
|
|
|
|
|
map_err:
|
|
|
|
drmModeRmFB(fb->fd, fb->id);
|
|
|
|
add_err:
|
|
|
|
memset(&darg, 0, sizeof(struct drm_mode_destroy_dumb));
|
|
|
|
darg.handle = fb->hdl;
|
|
|
|
drmIoctl(dev->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &darg);
|
|
|
|
create_err:
|
|
|
|
free(fb);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
|
|
|
ecore_drm_fb_destroy(Ecore_Drm_Fb *fb)
|
|
|
|
{
|
|
|
|
struct drm_mode_destroy_dumb darg;
|
|
|
|
|
|
|
|
if ((!fb) || (!fb->mmap)) return;
|
|
|
|
|
|
|
|
if (fb->id) drmModeRmFB(fb->fd, fb->id);
|
|
|
|
munmap(fb->mmap, fb->size);
|
|
|
|
memset(&darg, 0, sizeof(struct drm_mode_destroy_dumb));
|
|
|
|
darg.handle = fb->hdl;
|
|
|
|
drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &darg);
|
|
|
|
free(fb);
|
|
|
|
}
|
2015-04-07 09:41:07 -07:00
|
|
|
|
|
|
|
EAPI void
|
|
|
|
ecore_drm_fb_dirty(Ecore_Drm_Fb *fb, Eina_Rectangle *rects, unsigned int count)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN(fb);
|
2015-06-03 09:59:07 -07:00
|
|
|
|
|
|
|
if ((!rects) || (!count)) return;
|
2015-04-07 09:41:07 -07:00
|
|
|
|
|
|
|
#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;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = drmModeDirtyFB(fb->fd, fb->id, clip, count);
|
|
|
|
if (ret)
|
|
|
|
{
|
|
|
|
if (ret == -EINVAL)
|
|
|
|
ERR("Could not mark FB as Dirty: %m");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
2015-04-08 10:41:35 -07:00
|
|
|
|
|
|
|
EAPI void
|
|
|
|
ecore_drm_fb_set(Ecore_Drm_Device *dev, Ecore_Drm_Fb *fb)
|
|
|
|
{
|
|
|
|
Ecore_Drm_Output *output;
|
|
|
|
Eina_List *l;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN(dev);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN(fb);
|
|
|
|
|
2015-11-04 06:40:54 -08:00
|
|
|
if (dev->dumb[0])
|
2015-04-08 10:41:35 -07:00
|
|
|
{
|
2015-11-04 06:40:54 -08:00
|
|
|
if ((fb->w != dev->dumb[0]->w) || (fb->h != dev->dumb[0]->h))
|
|
|
|
{
|
|
|
|
/* we need to copy from fb to dev->dumb */
|
|
|
|
WRN("Trying to set a Framebuffer of improper size !!");
|
|
|
|
return;
|
|
|
|
}
|
2015-04-08 10:41:35 -07:00
|
|
|
}
|
|
|
|
|
2015-05-13 11:33:08 -07:00
|
|
|
if (!dev->next) dev->next = fb;
|
|
|
|
if (!dev->next) return;
|
|
|
|
|
2015-04-08 10:41:35 -07:00
|
|
|
EINA_LIST_FOREACH(dev->outputs, l, output)
|
|
|
|
{
|
|
|
|
int x = 0, y = 0;
|
|
|
|
|
2015-05-13 11:33:08 -07:00
|
|
|
if ((!output->enabled) || (!output->current_mode)) continue;
|
|
|
|
|
2015-04-08 10:41:35 -07:00
|
|
|
if (!output->cloned)
|
|
|
|
{
|
|
|
|
x = output->x;
|
|
|
|
y = output->y;
|
|
|
|
}
|
|
|
|
|
2015-05-13 11:33:08 -07:00
|
|
|
if ((!dev->current) ||
|
|
|
|
(dev->current->stride != dev->next->stride))
|
2015-04-08 10:41:35 -07:00
|
|
|
{
|
2015-05-13 11:33:08 -07:00
|
|
|
if (drmModeSetCrtc(dev->drm.fd, output->crtc_id, dev->next->id,
|
|
|
|
x, y, &output->conn_id, 1,
|
|
|
|
&output->current_mode->info))
|
|
|
|
{
|
|
|
|
ERR("Failed to set Mode %dx%d for Output %s: %m",
|
|
|
|
output->current_mode->width, output->current_mode->height,
|
|
|
|
output->name);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* TODO: set dpms on ?? */
|
2015-04-08 10:41:35 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
|
|
|
ecore_drm_fb_send(Ecore_Drm_Device *dev, Ecore_Drm_Fb *fb, Ecore_Drm_Pageflip_Cb func, void *data)
|
|
|
|
{
|
|
|
|
Ecore_Drm_Output *output;
|
|
|
|
Eina_List *l;
|
|
|
|
Ecore_Drm_Pageflip_Callback *cb;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN(dev);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN(fb);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN(func);
|
|
|
|
|
|
|
|
if (eina_list_count(dev->outputs) < 1) return;
|
|
|
|
|
|
|
|
if (!(cb = calloc(1, sizeof(Ecore_Drm_Pageflip_Callback))))
|
|
|
|
return;
|
|
|
|
|
2015-05-13 11:33:08 -07:00
|
|
|
cb->dev = dev;
|
2015-04-08 10:41:35 -07:00
|
|
|
cb->func = func;
|
|
|
|
cb->data = data;
|
2015-05-13 11:33:08 -07:00
|
|
|
|
|
|
|
EINA_LIST_FOREACH(dev->outputs, l, output)
|
|
|
|
if (output->enabled) cb->count++;
|
|
|
|
|
2015-04-08 10:41:35 -07:00
|
|
|
EINA_LIST_FOREACH(dev->outputs, l, output)
|
|
|
|
{
|
2015-05-13 11:33:08 -07:00
|
|
|
if ((!output->enabled) || (!output->current_mode)) continue;
|
|
|
|
|
2015-04-08 10:41:35 -07:00
|
|
|
if (drmModePageFlip(dev->drm.fd, output->crtc_id, fb->id,
|
|
|
|
DRM_MODE_PAGE_FLIP_EVENT, cb) < 0)
|
|
|
|
{
|
|
|
|
ERR("Cannot flip crtc %u for connector %u: %m",
|
|
|
|
output->crtc_id, output->conn_id);
|
2015-04-16 07:22:44 -07:00
|
|
|
continue;
|
2015-04-08 10:41:35 -07:00
|
|
|
}
|
2015-04-16 07:22:44 -07:00
|
|
|
|
|
|
|
fb->pending_flip = EINA_TRUE;
|
2015-04-08 10:41:35 -07:00
|
|
|
}
|
2015-04-16 07:22:44 -07:00
|
|
|
|
|
|
|
while (fb->pending_flip)
|
2015-11-04 09:44:29 -08:00
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
ret = drmHandleEvent(dev->drm.fd, &dev->drm_ctx);
|
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
ERR("drmHandleEvent Failed: %m");
|
|
|
|
free(cb);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2015-04-08 10:41:35 -07:00
|
|
|
}
|