aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--GNUmakefile7
-rw-r--r--drmtools-egl.c195
-rw-r--r--drmtools.c95
-rw-r--r--drmtools.h15
-rw-r--r--fbiconfig.c6
-rw-r--r--fbiconfig.h3
-rw-r--r--fbpdf.c59
-rw-r--r--gfx.h7
8 files changed, 321 insertions, 66 deletions
diff --git a/GNUmakefile b/GNUmakefile
index 59fa543..4da1485 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -192,12 +192,13 @@ fbi: $(OBJS_FBI) $(OBJS_READER)
# object files
OBJS_FBPDF := \
- fbpdf.o vt.o kbd.o fbtools.o drmtools.o \
+ fbpdf.o vt.o kbd.o fbtools.o drmtools.o drmtools-egl.o \
fbiconfig.o parseconfig.o
+PKGS_FBPDF := libdrm poppler-glib gbm epoxy cairo-gl
# font + drm + jpeg/exif libs
-fbpdf : CFLAGS += $(shell $(PKG_CONFIG) --cflags libdrm poppler-glib)
-fbpdf : LDLIBS += $(shell $(PKG_CONFIG) --libs libdrm poppler-glib)
+fbpdf : CFLAGS += $(shell $(PKG_CONFIG) --cflags $(PKGS_FBPDF))
+fbpdf : LDLIBS += $(shell $(PKG_CONFIG) --libs $(PKGS_FBPDF))
fbpdf: $(OBJS_FBPDF)
diff --git a/drmtools-egl.c b/drmtools-egl.c
new file mode 100644
index 0000000..8c91c0f
--- /dev/null
+++ b/drmtools-egl.c
@@ -0,0 +1,195 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <inttypes.h>
+#include <getopt.h>
+
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#include <gbm.h>
+#include <epoxy/gl.h>
+#include <epoxy/egl.h>
+
+#include "gfx.h"
+#include "drmtools.h"
+
+/* ------------------------------------------------------------------ */
+
+static struct gbm_device *gbm_dev;
+static struct gbm_surface *gbm_surface;
+static EGLDisplay dpy;
+static EGLConfig cfg;
+static EGLContext ctx;
+static EGLSurface surface;
+
+/* ------------------------------------------------------------------ */
+
+static int drm_setup_egl(void)
+{
+ static const EGLint conf_att[] = {
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RED_SIZE, 5,
+ EGL_GREEN_SIZE, 5,
+ EGL_BLUE_SIZE, 5,
+ EGL_ALPHA_SIZE, 0,
+ EGL_NONE,
+ };
+ static const EGLint ctx_att[] = {
+ EGL_NONE
+ };
+ EGLint major, minor;
+ EGLBoolean b;
+ EGLint n;
+
+ gbm_dev = gbm_create_device(drm_fd);
+ if (!gbm_dev) {
+ fprintf(stderr, "egl: gbm_create_device failed\n");
+ return -1;
+ }
+
+ gbm_surface = gbm_surface_create(gbm_dev,
+ drm_mode->hdisplay,
+ drm_mode->vdisplay,
+ GBM_FORMAT_XRGB8888,
+ GBM_BO_USE_RENDERING);
+ if (!gbm_surface) {
+ fprintf(stderr, "egl: gbm_create_surface failed\n");
+ return -1;
+ }
+
+ dpy = eglGetDisplay(gbm_dev);
+ if (dpy == EGL_NO_DISPLAY) {
+ fprintf(stderr, "egl: eglGetDisplay failed\n");
+ return -1;
+ }
+
+ b = eglInitialize(dpy, &major, &minor);
+ if (b == EGL_FALSE) {
+ fprintf(stderr, "egl: eglInitialize failed\n");
+ return -1;
+ }
+
+ b = eglBindAPI(EGL_OPENGL_API);
+ if (b == EGL_FALSE) {
+ fprintf(stderr, "egl: eglBindAPI failed\n");
+ return -1;
+ }
+
+ b = eglChooseConfig(dpy, conf_att, &cfg, 1, &n);
+ if (b == EGL_FALSE || n != 1) {
+ fprintf(stderr, "egl: eglChooseConfig failed\n");
+ return -1;
+ }
+
+ ctx = eglCreateContext(dpy, cfg, EGL_NO_CONTEXT, ctx_att);
+ if (ctx == EGL_NO_CONTEXT) {
+ fprintf(stderr, "egl: eglCreateContext failed\n");
+ return -1;
+ }
+
+ b = eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, ctx);
+ if (b == EGL_FALSE) {
+ fprintf(stderr, "egl: eglMakeCurrent(EGL_NO_SURFACE) failed\n");
+ return -1;
+ }
+
+ surface = eglCreateWindowSurface(dpy, cfg,
+ (EGLNativeWindowType)gbm_surface,
+ NULL);
+ if (!surface) {
+ fprintf(stderr, "egl: eglCreateWindowSurface failed\n");
+ return -1;
+ }
+
+ b = eglMakeCurrent(dpy, surface, surface, ctx);
+ if (b == EGL_FALSE) {
+ fprintf(stderr, "egl: eglMakeCurrent(surface) failed\n");
+ return -1;
+ }
+ return 0;
+}
+
+static void drm_egl_restore_display(void)
+{
+ /* FIXME */
+}
+
+static int fbid;
+static struct gbm_bo *bo;
+
+/* called after cairo_gl_surface_swapbuffers(); */
+static void drm_egl_flush_display(bool second)
+{
+ uint32_t handle, stride, newfb;
+ struct gbm_bo *newbo;
+ int rc;
+
+ newbo = gbm_surface_lock_front_buffer(gbm_surface);
+ if (!newbo) {
+ fprintf(stderr, "egl: gbm_surface_lock_front_buffer failed\n");
+ return;
+ }
+ handle = gbm_bo_get_handle(newbo).u32;
+ stride = gbm_bo_get_stride(newbo);
+
+ drmModeAddFB(drm_fd, drm_mode->hdisplay, drm_mode->vdisplay, 24, 32,
+ stride, handle, &newfb);
+ rc = drmModeSetCrtc(drm_fd, drm_enc->crtc_id, newfb, 0, 0,
+ &drm_conn->connector_id, 1,
+ &drm_conn->modes[0]);
+ if (rc < 0) {
+ fprintf(stderr, "egl: drmModeSetCrtc() failed\n");
+ return;
+ }
+
+ if (fbid) {
+ drmModeRmFB(drm_fd, fbid);
+ }
+ fbid = newfb;
+
+ if (bo) {
+ gbm_surface_release_buffer(gbm_surface, bo);
+ }
+ bo = newbo;
+}
+
+gfxstate *drm_init_egl(const char *device, const char *output)
+{
+ gfxstate *gfx;
+ char dev[64];
+
+ if (device) {
+ snprintf(dev, sizeof(dev), "%s", device);
+ } else {
+ snprintf(dev, sizeof(dev), DRM_DEV_NAME, DRM_DIR_NAME, 0);
+ }
+ fprintf(stderr, "trying drm/egl: %s ...\n", dev);
+
+ if (drm_init_dev(dev, output) < 0)
+ return NULL;
+ if (drm_setup_egl() < 0)
+ return NULL;
+
+ /* prepare gfx */
+ gfx = malloc(sizeof(*gfx));
+ memset(gfx, 0, sizeof(*gfx));
+
+ gfx->hdisplay = drm_mode->hdisplay;
+ gfx->vdisplay = drm_mode->vdisplay;
+
+ gfx->dpy = dpy;
+ gfx->ctx = ctx;
+ gfx->surface = surface;
+
+ gfx->restore_display = drm_egl_restore_display;
+ gfx->cleanup_display = drm_cleanup_display;
+ gfx->flush_display = drm_egl_flush_display;
+
+ return gfx;
+}
diff --git a/drmtools.c b/drmtools.c
index 38c4f35..dee8150 100644
--- a/drmtools.c
+++ b/drmtools.c
@@ -11,19 +11,16 @@
#include <sys/ioctl.h>
#include <sys/mman.h>
-#include <xf86drm.h>
-#include <xf86drmMode.h>
-
#include "gfx.h"
#include "drmtools.h"
/* ------------------------------------------------------------------ */
/* device */
-static int fd;
-static drmModeConnector *conn = NULL;
-static drmModeEncoder *enc = NULL;
-static drmModeModeInfo *mode = NULL;
+int drm_fd;
+drmModeEncoder *drm_enc = NULL;
+drmModeModeInfo *drm_mode = NULL;
+drmModeConnector *drm_conn = NULL;
static drmModeCrtc *scrtc = NULL;
struct drmfb {
@@ -69,16 +66,16 @@ static void drm_conn_name(drmModeConnector *conn, char *dest, int dlen)
/* ------------------------------------------------------------------ */
-static void drm_cleanup_display(void)
+void drm_cleanup_display(void)
{
/* restore crtc */
if (scrtc) {
- drmModeSetCrtc(fd, scrtc->crtc_id, scrtc->buffer_id, scrtc->x, scrtc->y,
- &conn->connector_id, 1, &scrtc->mode);
+ drmModeSetCrtc(drm_fd, scrtc->crtc_id, scrtc->buffer_id, scrtc->x, scrtc->y,
+ &drm_conn->connector_id, 1, &scrtc->mode);
}
}
-static int drm_init_dev(const char *dev, const char *output)
+int drm_init_dev(const char *dev, const char *output)
{
drmModeRes *res;
char name[64];
@@ -86,31 +83,31 @@ static int drm_init_dev(const char *dev, const char *output)
int i, rc;
/* open device */
- fd = open(dev, O_RDWR);
- if (fd < 0) {
+ drm_fd = open(dev, O_RDWR);
+ if (drm_fd < 0) {
fprintf(stderr, "drm: open %s: %s\n", dev, strerror(errno));
return -1;
}
- rc = drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &has_dumb);
+ rc = drmGetCap(drm_fd, DRM_CAP_DUMB_BUFFER, &has_dumb);
if (rc < 0 || !has_dumb) {
fprintf(stderr, "drm: no dumb buffer support\n");
return -1;
}
/* find connector (using first for now) */
- res = drmModeGetResources(fd);
+ res = drmModeGetResources(drm_fd);
if (res == NULL) {
fprintf(stderr, "drm: drmModeGetResources() failed\n");
return -1;
}
for (i = 0; i < res->count_connectors; i++) {
- conn = drmModeGetConnector(fd, res->connectors[i]);
- if (conn &&
- (conn->connection == DRM_MODE_CONNECTED) &&
- conn->count_modes) {
+ drm_conn = drmModeGetConnector(drm_fd, res->connectors[i]);
+ if (drm_conn &&
+ (drm_conn->connection == DRM_MODE_CONNECTED) &&
+ drm_conn->count_modes) {
if (output) {
- drm_conn_name(conn, name, sizeof(name));
+ drm_conn_name(drm_conn, name, sizeof(name));
if (strcmp(name, output) == 0) {
break;
}
@@ -118,10 +115,10 @@ static int drm_init_dev(const char *dev, const char *output)
break;
}
}
- drmModeFreeConnector(conn);
- conn = NULL;
+ drmModeFreeConnector(drm_conn);
+ drm_conn = NULL;
}
- if (!conn) {
+ if (!drm_conn) {
if (output) {
fprintf(stderr, "drm: output %s not found or disconnected\n",
output);
@@ -130,15 +127,15 @@ static int drm_init_dev(const char *dev, const char *output)
}
return -1;
}
- mode = &conn->modes[0];
- enc = drmModeGetEncoder(fd, conn->encoder_id);
- if (enc == NULL) {
+ drm_mode = &drm_conn->modes[0];
+ drm_enc = drmModeGetEncoder(drm_fd, drm_conn->encoder_id);
+ if (drm_enc == NULL) {
fprintf(stderr, "drm: drmModeGetEncoder() failed\n");
return -1;
}
/* save crtc */
- scrtc = drmModeGetCrtc(fd, enc->crtc_id);
+ scrtc = drmModeGetCrtc(drm_fd, drm_enc->crtc_id);
return 0;
}
@@ -149,15 +146,15 @@ static int drm_init_fb(struct drmfb *fb)
/* create framebuffer */
memset(&fb->creq, 0, sizeof(fb->creq));
- fb->creq.width = mode->hdisplay;
- fb->creq.height = mode->vdisplay;
+ fb->creq.width = drm_mode->hdisplay;
+ fb->creq.height = drm_mode->vdisplay;
fb->creq.bpp = 32;
- rc = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &fb->creq);
+ rc = drmIoctl(drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &fb->creq);
if (rc < 0) {
fprintf(stderr, "drm: DRM_IOCTL_MODE_CREATE_DUMB: %s\n", strerror(errno));
return -1;
}
- rc = drmModeAddFB(fd, fb->creq.width, fb->creq.height,
+ rc = drmModeAddFB(drm_fd, fb->creq.width, fb->creq.height,
24, 32, fb->creq.pitch,
fb->creq.handle, &fb->id);
if (rc < 0) {
@@ -168,13 +165,13 @@ static int drm_init_fb(struct drmfb *fb)
/* map framebuffer */
memset(&mreq, 0, sizeof(mreq));
mreq.handle = fb->creq.handle;
- rc = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);
+ rc = drmIoctl(drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);
if (rc < 0) {
fprintf(stderr, "drm: DRM_IOCTL_MODE_MAP_DUMB: %s\n", strerror(errno));
return -1;
}
fb->mem = mmap(0, fb->creq.size, PROT_READ | PROT_WRITE, MAP_SHARED,
- fd, mreq.offset);
+ drm_fd, mreq.offset);
if (fb->mem == MAP_FAILED) {
fprintf(stderr, "drm: framebuffer mmap: %s\n", strerror(errno));
return -1;
@@ -186,9 +183,9 @@ static int drm_show_fb(struct drmfb *fb)
{
int rc;
- rc = drmModeSetCrtc(fd, enc->crtc_id, fb->id, 0, 0,
- &conn->connector_id, 1,
- &conn->modes[0]);
+ rc = drmModeSetCrtc(drm_fd, drm_enc->crtc_id, fb->id, 0, 0,
+ &drm_conn->connector_id, 1,
+ &drm_conn->modes[0]);
if (rc < 0) {
fprintf(stderr, "drm: drmModeSetCrtc() failed\n");
return -1;
@@ -207,7 +204,7 @@ static void drm_flush_display(bool second)
{
fbc = second ? &fb2 : &fb1;
drm_show_fb(fbc);
- drmModeDirtyFB(fd, fbc->id, 0, 0);
+ drmModeDirtyFB(drm_fd, fbc->id, 0, 0);
}
gfxstate *drm_init(const char *device, const char *output, bool pageflip)
@@ -233,8 +230,8 @@ gfxstate *drm_init(const char *device, const char *output, bool pageflip)
gfx = malloc(sizeof(*gfx));
memset(gfx, 0, sizeof(*gfx));
- gfx->hdisplay = mode->hdisplay;
- gfx->vdisplay = mode->vdisplay;
+ gfx->hdisplay = drm_mode->hdisplay;
+ gfx->vdisplay = drm_mode->vdisplay;
gfx->stride = fb1.creq.pitch;
gfx->mem = fb1.mem;
@@ -262,6 +259,8 @@ gfxstate *drm_init(const char *device, const char *output, bool pageflip)
return gfx;
}
+/* ------------------------------------------------------------------ */
+
void drm_info(const char *device)
{
drmModeConnector *conn;
@@ -277,36 +276,36 @@ void drm_info(const char *device)
} else {
snprintf(dev, sizeof(dev), DRM_DEV_NAME, DRM_DIR_NAME, 0);
}
- fd = open(dev, O_RDWR);
- if (fd < 0) {
+ drm_fd = open(dev, O_RDWR);
+ if (drm_fd < 0) {
fprintf(stderr, "drm: open %s: %s\n", dev, strerror(errno));
return;
}
fprintf(stdout, "connectors for %s:\n", dev);
- res = drmModeGetResources(fd);
+ res = drmModeGetResources(drm_fd);
if (res == NULL) {
return;
}
for (i = 0; i < res->count_connectors; i++) {
- conn = drmModeGetConnector(fd, res->connectors[i]);
+ conn = drmModeGetConnector(drm_fd, res->connectors[i]);
if (!conn)
continue;
- if (!conn->count_encoders)
+ if (!drm_conn->count_encoders)
return;
drm_conn_name(conn, name, sizeof(name));
enc = NULL;
crtc = NULL;
- if (conn->encoder_id) {
- enc = drmModeGetEncoder(fd, conn->encoder_id);
+ if (drm_conn->encoder_id) {
+ enc = drmModeGetEncoder(drm_fd, drm_conn->encoder_id);
if (enc && enc->crtc_id) {
- crtc = drmModeGetCrtc(fd, enc->crtc_id);
+ crtc = drmModeGetCrtc(drm_fd, enc->crtc_id);
}
}
- if (conn->connection == DRM_MODE_CONNECTED && crtc) {
+ if (drm_conn->connection == DRM_MODE_CONNECTED && crtc) {
fprintf(stdout, " %s, connected, %dx%d\n", name,
crtc->width, crtc->height);
} else {
diff --git a/drmtools.h b/drmtools.h
index cbb6afb..0def894 100644
--- a/drmtools.h
+++ b/drmtools.h
@@ -1,2 +1,17 @@
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+/* internal */
+extern int drm_fd;
+extern drmModeEncoder *drm_enc;
+extern drmModeModeInfo *drm_mode;
+extern drmModeConnector *drm_conn;
+void drm_cleanup_display(void);
+int drm_init_dev(const char *dev, const char *output);
+
+/* drmtools.c */
gfxstate *drm_init(const char *device, const char *output, bool pageflip);
void drm_info(const char *device);
+
+/* drmtools-egl.c */
+gfxstate *drm_init_egl(const char *device, const char *output);
diff --git a/fbiconfig.c b/fbiconfig.c
index 460c46a..39da0bc 100644
--- a/fbiconfig.c
+++ b/fbiconfig.c
@@ -229,6 +229,12 @@ struct cfg_cmdline fbpdf_cfg[] = {
.needsarg = 1,
.desc = "use drm output <arg> (try -info for a list)",
},{
+ .letter = 'g',
+ .cmdline = "opengl",
+ .option = { O_OPENGL },
+ .yesno = 1,
+ .desc = "use opengl",
+ },{
.letter = 'm',
.cmdline = "mode",
.option = { O_VIDEO_MODE },
diff --git a/fbiconfig.h b/fbiconfig.h
index f5e0c03..3cd5d7d 100644
--- a/fbiconfig.h
+++ b/fbiconfig.h
@@ -33,6 +33,7 @@
#define O_DEVICE O_OPTIONS, "device"
#define O_OUTPUT O_OPTIONS, "output"
+#define O_OPENGL O_OPTIONS, "opengl"
#define O_FONT O_OPTIONS, "font"
#define O_VIDEO_MODE O_OPTIONS, "video-mode"
@@ -63,6 +64,8 @@
#define GET_TIMEOUT() cfg_get_int(O_TIMEOUT, 0)
#define GET_PCD_RES() cfg_get_int(O_PCD_RES, 3)
+#define GET_OPENGL() cfg_get_bool(O_OPENGL, 0)
+
/* -------------------------------------------------------------------------- */
extern struct cfg_cmdline fbi_cmd[];
diff --git a/fbpdf.c b/fbpdf.c
index e91cfe4..c97edc1 100644
--- a/fbpdf.c
+++ b/fbpdf.c
@@ -31,6 +31,10 @@
#include <linux/fb.h>
#include <poppler.h>
+#include <cairo.h>
+
+#include <epoxy/egl.h>
+#include <cairo-gl.h>
#include "vt.h"
#include "kbd.h"
@@ -52,6 +56,7 @@ int debug;
PopplerDocument *doc;
cairo_surface_t *surface1;
cairo_surface_t *surface2;
+cairo_surface_t *surfacegl;
/* pdf render state */
PopplerPage *page;
@@ -132,19 +137,25 @@ static void page_render(void)
static bool second;
cairo_t *context;
- if (surface2)
- second = !second;
- context = cairo_create(second ? surface2 : surface1);
-
- cairo_set_source_rgb(context, 1, 1, 1);
- cairo_paint(context);
+ if (surfacegl) {
+ context = cairo_create(surfacegl);
+ } else {
+ if (surface2)
+ second = !second;
+ context = cairo_create(second ? surface2 : surface1);
+ }
cairo_translate(context, tx, ty);
cairo_scale(context, scale, scale);
+ cairo_set_source_rgb(context, 1, 1, 1);
+ cairo_paint(context);
poppler_page_render(page, context);
cairo_show_page(context);
cairo_destroy(context);
+ if (surfacegl) {
+ cairo_gl_surface_swapbuffers(surfacegl);
+ }
if (gfx->flush_display)
gfx->flush_display(second);
}
@@ -293,14 +304,24 @@ int main(int argc, char *argv[])
if (device) {
/* device specified */
if (strncmp(device, "/dev/d", 6) == 0) {
- gfx = drm_init(device, output, true);
+ if (GET_OPENGL()) {
+ gfx = drm_init_egl(device, output);
+ }
+ if (!gfx) {
+ gfx = drm_init(device, output, true);
+ }
} else {
framebuffer = true;
gfx = fb_init(device, mode, GET_VT());
}
} else {
/* try drm first, failing that fb */
- gfx = drm_init(NULL, output, true);
+ if (GET_OPENGL()) {
+ gfx = drm_init_egl(NULL, output);
+ }
+ if (!gfx) {
+ gfx = drm_init(NULL, output, true);
+ }
if (!gfx) {
framebuffer = true;
gfx = fb_init(NULL, mode, GET_VT());
@@ -322,17 +343,25 @@ int main(int argc, char *argv[])
}
}
- surface1 = cairo_image_surface_create_for_data(gfx->mem,
- CAIRO_FORMAT_ARGB32,
- gfx->hdisplay,
- gfx->vdisplay,
- gfx->stride);
- if (gfx->mem2) {
- surface2 = cairo_image_surface_create_for_data(gfx->mem2,
+ if (gfx->mem) {
+ surface1 = cairo_image_surface_create_for_data(gfx->mem,
CAIRO_FORMAT_ARGB32,
gfx->hdisplay,
gfx->vdisplay,
gfx->stride);
+ if (gfx->mem2) {
+ surface2 = cairo_image_surface_create_for_data(gfx->mem2,
+ CAIRO_FORMAT_ARGB32,
+ gfx->hdisplay,
+ gfx->vdisplay,
+ gfx->stride);
+ }
+ } else {
+ cairo_device_t *dev;
+ dev = cairo_egl_device_create(gfx->dpy, gfx->ctx);
+ surfacegl = cairo_gl_surface_create_for_egl(dev, gfx->surface,
+ gfx->hdisplay,
+ gfx->vdisplay);
}
tty_raw();
diff --git a/gfx.h b/gfx.h
index 16d25fa..f3602c6 100644
--- a/gfx.h
+++ b/gfx.h
@@ -1,6 +1,8 @@
#include <stdbool.h>
#include <inttypes.h>
+#include <epoxy/egl.h>
+
typedef struct gfxstate gfxstate;
struct gfxstate {
@@ -15,6 +17,11 @@ struct gfxstate {
uint32_t rlen, glen, blen, tlen;
uint32_t roff, goff, boff, toff;
+ /* egl */
+ EGLDisplay dpy;
+ EGLContext ctx;
+ EGLSurface surface;
+
/* calls */
void (*restore_display)(void);
void (*cleanup_display)(void);