diff options
-rw-r--r-- | GNUmakefile | 7 | ||||
-rw-r--r-- | drmtools-egl.c | 195 | ||||
-rw-r--r-- | drmtools.c | 95 | ||||
-rw-r--r-- | drmtools.h | 15 | ||||
-rw-r--r-- | fbiconfig.c | 6 | ||||
-rw-r--r-- | fbiconfig.h | 3 | ||||
-rw-r--r-- | fbpdf.c | 59 | ||||
-rw-r--r-- | gfx.h | 7 |
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; +} @@ -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 { @@ -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[]; @@ -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(); @@ -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); |