summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Michael <cpmichael@osg.samsung.com>2016-05-02 11:45:39 -0400
committerChris Michael <cpmichael@osg.samsung.com>2016-05-27 11:57:53 -0400
commitd2b4176592c6f0e6bd2a78c7a620f29142b65575 (patch)
tree290680b097e2a9a7fb3674432baa47c737f2bb42
parent4e38aabdc09df1ef4ad630caa7fe754433a35d7d (diff)
downloadefl-d2b4176592c6f0e6bd2a78c7a620f29142b65575.tar.gz
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>
-rw-r--r--src/Makefile_Ecore_Drm2.am1
-rw-r--r--src/lib/ecore_drm2/Ecore_Drm2.h122
-rw-r--r--src/lib/ecore_drm2/ecore_drm2_fb.c265
-rw-r--r--src/lib/ecore_drm2/ecore_drm2_outputs.c14
4 files changed, 401 insertions, 1 deletions
diff --git a/src/Makefile_Ecore_Drm2.am b/src/Makefile_Ecore_Drm2.am
index ab401c625f..1c328e33de 100644
--- a/src/Makefile_Ecore_Drm2.am
+++ b/src/Makefile_Ecore_Drm2.am
@@ -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 \
diff --git a/src/lib/ecore_drm2/Ecore_Drm2.h b/src/lib/ecore_drm2/Ecore_Drm2.h
index 0bed771489..f1ce291651 100644
--- a/src/lib/ecore_drm2/Ecore_Drm2.h
+++ b/src/lib/ecore_drm2/Ecore_Drm2.h
@@ -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
diff --git a/src/lib/ecore_drm2/ecore_drm2_fb.c b/src/lib/ecore_drm2/ecore_drm2_fb.c
new file mode 100644
index 0000000000..9032c122be
--- /dev/null
+++ b/src/lib/ecore_drm2/ecore_drm2_fb.c
@@ -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;
+}
diff --git a/src/lib/ecore_drm2/ecore_drm2_outputs.c b/src/lib/ecore_drm2/ecore_drm2_outputs.c
index d7f1c39f03..6443ecaf1a 100644
--- a/src/lib/ecore_drm2/ecore_drm2_outputs.c
+++ b/src/lib/ecore_drm2/ecore_drm2_outputs.c
@@ -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;
+}