diff options
| -rw-r--r-- | src/Makefile.am | 2 | ||||
| -rw-r--r-- | src/drm_fb.c | 157 | ||||
| -rw-r--r-- | src/drm_fb.h | 12 | 
3 files changed, 170 insertions, 1 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 556d193..59ba58c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,5 +1,5 @@  SUBDIRS = modules  bin_PROGRAMS = rototiller -rototiller_SOURCES = drmsetup.c drmsetup.h fb.c fb.h fps.c fps.h rototiller.c rototiller.h threads.c threads.h util.c util.h +rototiller_SOURCES = drmsetup.c drmsetup.h drm_fb.c drm_fb.h fb.c fb.h fps.c fps.h rototiller.c rototiller.h threads.c threads.h util.c util.h  rototiller_LDADD = @ROTOTILLER_LIBS@ -lm modules/julia/libjulia.a modules/plasma/libplasma.a modules/ray/libray.a modules/roto/libroto.a modules/sparkler/libsparkler.a modules/stars/libstars.a  rototiller_CPPFLAGS = @ROTOTILLER_CFLAGS@ diff --git a/src/drm_fb.c b/src/drm_fb.c new file mode 100644 index 0000000..99169de --- /dev/null +++ b/src/drm_fb.c @@ -0,0 +1,157 @@ +#include <fcntl.h> +#include <inttypes.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <xf86drm.h> +#include <xf86drmMode.h> + +#include "fb.h" +#include "util.h" + + +/* drm fb backend, everything drm-specific in rototiller resides here. */ + +typedef struct drm_fb_t { +	int			drm_fd; +	uint32_t		crtc_id; +	uint32_t		*connectors; +	int			n_connectors; +	drmModeModeInfoPtr	mode; +} drm_fb_t; + +typedef struct drm_fb_page_t drm_fb_page_t; + +struct drm_fb_page_t { +	uint32_t		*mmap; +	size_t			mmap_size; +	uint32_t		drm_dumb_handle; +	uint32_t		drm_fb_id; +}; + + +drm_fb_t * drm_fb_new(int drm_fd, uint32_t crtc_id, uint32_t *connectors, int n_connectors, drmModeModeInfoPtr mode) +{ +	drm_fb_t	*c; + +	c = calloc(1, sizeof(drm_fb_t)); +	if (!c) +		return NULL; + +	c->drm_fd = drm_fd; +	c->crtc_id = crtc_id; +	c->connectors = connectors; +	c->n_connectors = n_connectors; +	c->mode = mode; + +	return c; +} + + +void drm_fb_free(drm_fb_t *context) +{ +	free(context); +} + + +static int drm_fb_acquire(void *context, void *page) +{ +	drm_fb_t	*c = context; +	drm_fb_page_t	*p = page; + +	return drmModeSetCrtc(c->drm_fd, c->crtc_id, p->drm_fb_id, 0, 0, c->connectors, c->n_connectors, c->mode); +} + + +static void drm_fb_release(void *context) +{ +	/* TODO restore the existing mode @ last acquire? */ +} + + +static void * drm_fb_page_alloc(void *context, fb_page_t *res_page) +{ +	struct drm_mode_create_dumb	create_dumb = { .bpp = 32 }; +	struct drm_mode_map_dumb	map_dumb = {}; +	uint32_t			*map, fb_id; +	drm_fb_t			*c = context; +	drm_fb_page_t			*p; + +	p = calloc(1, sizeof(drm_fb_page_t)); +	if (!p) +		return NULL; + +	create_dumb.width = c->mode->hdisplay; +	create_dumb.height = c->mode->vdisplay; + +	pexit_if(ioctl(c->drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb) < 0, +		"unable to create dumb buffer"); + +	map_dumb.handle = create_dumb.handle; +	pexit_if(ioctl(c->drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &map_dumb) < 0, +		"unable to prepare dumb buffer for mmap"); +	pexit_if(!(map = mmap(NULL, create_dumb.size, PROT_READ|PROT_WRITE, MAP_SHARED, c->drm_fd, map_dumb.offset)), +		"unable to mmap dumb buffer"); +	pexit_if(drmModeAddFB(c->drm_fd, c->mode->hdisplay, c->mode->vdisplay, 24, 32, create_dumb.pitch, create_dumb.handle, &fb_id) < 0, +		"unable to add dumb buffer"); + +	p->mmap = map; +	p->mmap_size = create_dumb.size; +	p->drm_dumb_handle = map_dumb.handle; +	p->drm_fb_id = fb_id; + +	res_page->fragment.buf = map; +	res_page->fragment.width = c->mode->hdisplay; +	res_page->fragment.frame_width = c->mode->hdisplay; +	res_page->fragment.height = c->mode->vdisplay; +	res_page->fragment.frame_height = c->mode->vdisplay; +	res_page->fragment.stride = create_dumb.pitch - (c->mode->hdisplay * 4); + +	return p; +} + + +static int drm_fb_page_free(void *context, void *page) +{ +	struct drm_mode_destroy_dumb	destroy_dumb = {}; +	drm_fb_t			*c = context; +	drm_fb_page_t			*p = page; + +	drmModeRmFB(c->drm_fd, p->drm_fb_id); +	munmap(p->mmap, p->mmap_size); + +	destroy_dumb.handle = p->drm_dumb_handle; +	ioctl(c->drm_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_dumb); // XXX: errors? + +	free(p); + +	return 0; +} + + +static int drm_fb_page_flip(void *context, void *page) +{ +	drmEventContext	drm_ev_ctx = { +				.version = DRM_EVENT_CONTEXT_VERSION, +				.vblank_handler = NULL, +				.page_flip_handler = NULL +			}; +	drm_fb_t	*c = context; +	drm_fb_page_t	*p = page; + +	if (drmModePageFlip(c->drm_fd, c->crtc_id, p->drm_fb_id, DRM_MODE_PAGE_FLIP_EVENT, NULL) < 0) +		return -1; + +	return drmHandleEvent(c->drm_fd, &drm_ev_ctx); +} + + +fb_ops_t drm_fb_ops = { +	.acquire = drm_fb_acquire, +	.release = drm_fb_release, +	.page_alloc = drm_fb_page_alloc, +	.page_free = drm_fb_page_free, +	.page_flip = drm_fb_page_flip +}; diff --git a/src/drm_fb.h b/src/drm_fb.h new file mode 100644 index 0000000..c283362 --- /dev/null +++ b/src/drm_fb.h @@ -0,0 +1,12 @@ +#ifndef _DRM_FB_H +#define _DRM_FB_H + +#include <stdint.h> +#include <xf86drmMode.h> + +typedef struct drm_fb_t drm_fb_t; + +drm_fb_t * drm_fb_new(int drm_fd, uint32_t crtc_id, uint32_t *connectors, int n_connectors, drmModeModeInfoPtr mode); +void drm_fb_free(drm_fb_t *fb); + +#endif  | 
