forked from enlightenment/efl
ecore-drm2: Add API functions to work with framebuffer objects
This patch adds support for creating, deleting, and manipulating framebuffer objects via exposed API. Signed-off-by: Chris Michael <cpmichael@osg.samsung.com>
This commit is contained in:
parent
4e38aabdc0
commit
d2b4176592
|
@ -9,6 +9,7 @@ dist_installed_ecoredrm2mainheaders_DATA = \
|
|||
lib/ecore_drm2/Ecore_Drm2.h
|
||||
|
||||
lib_ecore_drm2_libecore_drm2_la_SOURCES = \
|
||||
lib/ecore_drm2/ecore_drm2_fb.c \
|
||||
lib/ecore_drm2/ecore_drm2_outputs.c \
|
||||
lib/ecore_drm2/ecore_drm2_device.c \
|
||||
lib/ecore_drm2/ecore_drm2.c \
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
# define _ECORE_DRM2_H
|
||||
|
||||
# include <Ecore.h>
|
||||
# include <Elput.h>
|
||||
|
||||
# ifdef EAPI
|
||||
# undef EAPI
|
||||
|
@ -67,6 +66,7 @@ EAPI extern int ECORE_DRM2_EVENT_OUTPUT_CHANGED;
|
|||
* @li @ref Ecore_Drm2_Init_Group
|
||||
* @li @ref Ecore_Drm2_Device_Group
|
||||
* @li @ref Ecore_Drm2_Output_Group
|
||||
* @li @ref Ecore_Drm2_Fb_Group
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -302,6 +302,126 @@ EAPI void ecore_drm2_output_geometry_get(Ecore_Drm2_Output *output, int *x, int
|
|||
*/
|
||||
EAPI unsigned int ecore_drm2_output_crtc_get(Ecore_Drm2_Output *output);
|
||||
|
||||
/**
|
||||
* Return the next Ecore_Drm2_Fb to be used on a given output
|
||||
*
|
||||
* @param output
|
||||
*
|
||||
* @return The next Ecore_Drm2_Fb which is scheduled to to be flipped, or NULL otherwise
|
||||
*
|
||||
* @ingroup Ecore_Drm2_Output_Group
|
||||
* @since 1.18
|
||||
*/
|
||||
EAPI Ecore_Drm2_Fb *ecore_drm2_output_next_fb_get(Ecore_Drm2_Output *output);
|
||||
|
||||
/**
|
||||
* Set the next Ecore_Drm2_Fb to be used on a given output
|
||||
*
|
||||
* @param output
|
||||
* @param fb
|
||||
*
|
||||
* @ingroup Ecore_Drm2_Output_Group
|
||||
* @since 1.18
|
||||
*/
|
||||
EAPI void ecore_drm2_output_next_fb_set(Ecore_Drm2_Output *output, Ecore_Drm2_Fb *fb);
|
||||
|
||||
/**
|
||||
* @defgroup Ecore_Drm2_Fb_Group Drm framebuffer functions
|
||||
*
|
||||
* Functions that deal with setup of framebuffers
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a new framebuffer object
|
||||
*
|
||||
* @param fd
|
||||
* @param width
|
||||
* @param height
|
||||
* @param depth
|
||||
* @param bpp
|
||||
* @param format
|
||||
*
|
||||
* @return A newly create framebuffer object, or NULL on failure
|
||||
*
|
||||
* @ingroup Ecore_Drm2_Fb_Group
|
||||
* @since 1.18
|
||||
*/
|
||||
EAPI Ecore_Drm2_Fb *ecore_drm2_fb_create(int fd, int width, int height, int depth, int bpp, unsigned int format);
|
||||
|
||||
EAPI Ecore_Drm2_Fb *ecore_drm2_fb_gbm_create(int fd, int width, int height, int depth, int bpp, unsigned int format, unsigned int handle, unsigned int stride);
|
||||
|
||||
/**
|
||||
* Destroy a framebuffer object
|
||||
*
|
||||
* @param fb
|
||||
*
|
||||
* @ingroup Ecore_Drm2_Fb_Group
|
||||
* @since 1.18
|
||||
*/
|
||||
EAPI void ecore_drm2_fb_destroy(Ecore_Drm2_Fb *fb);
|
||||
|
||||
/**
|
||||
* Get a framebuffer's mmap'd data
|
||||
*
|
||||
* @param fb
|
||||
*
|
||||
* @return The mmap'd area of the framebuffer or NULL on failure
|
||||
*
|
||||
* @ingroup Ecore_Drm2_Fb_Group
|
||||
* @since 1.18
|
||||
*/
|
||||
EAPI void *ecore_drm2_fb_data_get(Ecore_Drm2_Fb *fb);
|
||||
|
||||
/**
|
||||
* Get a framebuffer's size
|
||||
*
|
||||
* @param fb
|
||||
*
|
||||
* @return size of the framebuffers' mmap'd data or 0 on failure
|
||||
*
|
||||
* @ingroup Ecore_Drm2_Fb_Group
|
||||
* @since 1.18
|
||||
*/
|
||||
EAPI unsigned int ecore_drm2_fb_size_get(Ecore_Drm2_Fb *fb);
|
||||
|
||||
/**
|
||||
* Get a framebuffer's stride
|
||||
*
|
||||
* @param fb
|
||||
*
|
||||
* @return stride of the framebuffer or 0 on failure
|
||||
*
|
||||
* @ingroup Ecore_Drm2_Fb_Group
|
||||
* @since 1.18
|
||||
*/
|
||||
EAPI unsigned int ecore_drm2_fb_stride_get(Ecore_Drm2_Fb *fb);
|
||||
|
||||
/**
|
||||
* Mark regions of a framebuffer as dirty
|
||||
*
|
||||
* @param fb
|
||||
* @param rects
|
||||
* @param count
|
||||
*
|
||||
* @ingroup Ecore_Drm2_Fb_Group
|
||||
* @since 1.18
|
||||
*/
|
||||
EAPI void ecore_drm2_fb_dirty(Ecore_Drm2_Fb *fb, Eina_Rectangle *rects, unsigned int count);
|
||||
|
||||
/**
|
||||
* Schedule a pageflip to the given Ecore_Drm2_Fb
|
||||
*
|
||||
* @param fb
|
||||
* @param output
|
||||
* @param data
|
||||
*
|
||||
* @return The result of drmModePageFlip function call
|
||||
*
|
||||
* @ingroup Ecore_Drm2_Fb_Group
|
||||
* @since 1.18
|
||||
*/
|
||||
EAPI int ecore_drm2_fb_flip(Ecore_Drm2_Fb *fb, Ecore_Drm2_Output *output, void *data);
|
||||
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,265 @@
|
|||
#include "ecore_drm2_private.h"
|
||||
|
||||
static Eina_Bool
|
||||
_fb2_create(Ecore_Drm2_Fb *fb)
|
||||
{
|
||||
struct drm_mode_fb_cmd2 cmd;
|
||||
uint32_t hdls[4], pitches[4], offsets[4];
|
||||
uint64_t modifiers[4];
|
||||
|
||||
hdls[0] = fb->hdl;
|
||||
pitches[0] = fb->stride;
|
||||
offsets[0] = 0;
|
||||
modifiers[0] = 0;
|
||||
|
||||
memset(&cmd, 0, sizeof(struct drm_mode_fb_cmd2));
|
||||
cmd.fb_id = 0;
|
||||
cmd.width = fb->w;
|
||||
cmd.height = fb->h;
|
||||
cmd.pixel_format = fb->format;
|
||||
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]));
|
||||
memcpy(cmd.modifier, modifiers, 4 * sizeof(modifiers[0]));
|
||||
|
||||
if (drmIoctl(fb->fd, DRM_IOCTL_MODE_ADDFB2, &cmd))
|
||||
return EINA_FALSE;
|
||||
|
||||
fb->id = cmd.fb_id;
|
||||
|
||||
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;
|
||||
struct drm_mode_create_dumb carg;
|
||||
struct drm_mode_destroy_dumb darg;
|
||||
struct drm_mode_map_dumb marg;
|
||||
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;
|
||||
|
||||
memset(&carg, 0, sizeof(struct drm_mode_create_dumb));
|
||||
carg.bpp = bpp;
|
||||
carg.width = width;
|
||||
carg.height = height;
|
||||
|
||||
ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &carg);
|
||||
if (ret) goto err;
|
||||
|
||||
fb->hdl = carg.handle;
|
||||
fb->size = carg.size;
|
||||
fb->stride = carg.pitch;
|
||||
|
||||
if (!_fb2_create(fb))
|
||||
{
|
||||
ret =
|
||||
drmModeAddFB(fd, width, height, depth, bpp,
|
||||
fb->stride, fb->hdl, &fb->id);
|
||||
if (ret)
|
||||
{
|
||||
ERR("Could not add framebuffer: %m");
|
||||
goto add_err;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&marg, 0, sizeof(struct drm_mode_map_dumb));
|
||||
marg.handle = fb->hdl;
|
||||
ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &marg);
|
||||
if (ret)
|
||||
{
|
||||
ERR("Could not map framebuffer: %m");
|
||||
goto map_err;
|
||||
}
|
||||
|
||||
fb->mmap = mmap(NULL, fb->size, PROT_WRITE, MAP_SHARED, fd, marg.offset);
|
||||
if (fb->mmap == MAP_FAILED)
|
||||
{
|
||||
ERR("Could not mmap framebuffer memory: %m");
|
||||
goto map_err;
|
||||
}
|
||||
|
||||
return fb;
|
||||
|
||||
map_err:
|
||||
drmModeRmFB(fd, fb->id);
|
||||
add_err:
|
||||
memset(&darg, 0, sizeof(struct drm_mode_destroy_dumb));
|
||||
darg.handle = fb->hdl;
|
||||
drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &darg);
|
||||
err:
|
||||
free(fb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EAPI Ecore_Drm2_Fb *
|
||||
ecore_drm2_fb_gbm_create(int fd, int width, int height, int depth, int bpp, unsigned int format, unsigned int handle, unsigned int stride)
|
||||
{
|
||||
Ecore_Drm2_Fb *fb;
|
||||
|
||||
EINA_SAFETY_ON_TRUE_RETURN_VAL((fd < 0), NULL);
|
||||
|
||||
fb = calloc(1, sizeof(Ecore_Drm2_Fb));
|
||||
if (!fb) return NULL;
|
||||
|
||||
fb->gbm = EINA_TRUE;
|
||||
|
||||
fb->fd = fd;
|
||||
fb->w = width;
|
||||
fb->h = height;
|
||||
fb->bpp = bpp;
|
||||
fb->depth = depth;
|
||||
fb->format = format;
|
||||
fb->stride = stride;
|
||||
fb->size = fb->stride * fb->h;
|
||||
fb->hdl = handle;
|
||||
|
||||
if (!_fb2_create(fb))
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret =
|
||||
drmModeAddFB(fd, width, height, depth, bpp,
|
||||
fb->stride, fb->hdl, &fb->id);
|
||||
if (ret)
|
||||
{
|
||||
ERR("Could not add framebuffer: %m");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
return fb;
|
||||
|
||||
err:
|
||||
free(fb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EAPI void
|
||||
ecore_drm2_fb_destroy(Ecore_Drm2_Fb *fb)
|
||||
{
|
||||
EINA_SAFETY_ON_NULL_RETURN(fb);
|
||||
|
||||
if (fb->id) drmModeRmFB(fb->fd, fb->id);
|
||||
|
||||
if (!fb->gbm)
|
||||
{
|
||||
struct drm_mode_destroy_dumb darg;
|
||||
|
||||
if (fb->mmap) 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);
|
||||
}
|
||||
|
||||
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);
|
||||
return fb->size;
|
||||
}
|
||||
|
||||
EAPI unsigned int
|
||||
ecore_drm2_fb_stride_get(Ecore_Drm2_Fb *fb)
|
||||
{
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(fb, 0);
|
||||
return fb->stride;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
ret = drmModeDirtyFB(fb->fd, fb->id, clip, count);
|
||||
if ((ret) && (ret == -EINVAL))
|
||||
WRN("Could not mark framebuffer as dirty: %m");
|
||||
#endif
|
||||
}
|
||||
|
||||
EAPI int
|
||||
ecore_drm2_fb_flip(Ecore_Drm2_Fb *fb, Ecore_Drm2_Output *output, void *data)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(fb, -1);
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(output, -1);
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(output->current_mode, -1);
|
||||
|
||||
if (output->next)
|
||||
WRN("Fb reused too soon, tearing may be visible");
|
||||
|
||||
if ((!output->current) ||
|
||||
(output->current->stride != fb->stride))
|
||||
{
|
||||
ret =
|
||||
drmModeSetCrtc(fb->fd, output->crtc_id, fb->id,
|
||||
output->x, output->y, &output->conn_id, 1,
|
||||
&output->current_mode->info);
|
||||
if (ret)
|
||||
{
|
||||
ERR("Failed to set Mode %dx%d for Output %s: %m",
|
||||
output->current_mode->width, output->current_mode->height,
|
||||
output->name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
output->current = fb;
|
||||
output->next = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret =
|
||||
drmModePageFlip(fb->fd, output->crtc_id, fb->id,
|
||||
DRM_MODE_PAGE_FLIP_EVENT, data);
|
||||
if (ret < 0)
|
||||
{
|
||||
DBG("Pageflip Failed for Crtc %u on Connector %u: %m",
|
||||
output->crtc_id, output->conn_id);
|
||||
output->next = fb;
|
||||
return ret;
|
||||
}
|
||||
|
||||
output->current = fb;
|
||||
return 0;
|
||||
}
|
|
@ -884,3 +884,17 @@ ecore_drm2_output_crtc_get(Ecore_Drm2_Output *output)
|
|||
EINA_SAFETY_ON_NULL_RETURN_VAL(output, 0);
|
||||
return output->crtc_id;
|
||||
}
|
||||
|
||||
EAPI Ecore_Drm2_Fb *
|
||||
ecore_drm2_output_next_fb_get(Ecore_Drm2_Output *output)
|
||||
{
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(output, NULL);
|
||||
return output->next;
|
||||
}
|
||||
|
||||
EAPI void
|
||||
ecore_drm2_output_next_fb_set(Ecore_Drm2_Output *output, Ecore_Drm2_Fb *fb)
|
||||
{
|
||||
EINA_SAFETY_ON_NULL_RETURN(output);
|
||||
output->next = fb;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue