Skip to content

Commit

Permalink
Framebuffer version can now be built for Linux framebuffer (what we'v…
Browse files Browse the repository at this point in the history
…e had all along) or for DRM = Direct Rendering Manager (works on Linux and *BSD).
  • Loading branch information
Bill-Gray committed Aug 21, 2022
1 parent 4683fdb commit e9bc09c
Show file tree
Hide file tree
Showing 7 changed files with 342 additions and 37 deletions.
2 changes: 1 addition & 1 deletion curses.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Defined by this header:
#define PDC_VER_CHANGE 4
#define PDC_VER_YEAR 2022
#define PDC_VER_MONTH 8
#define PDC_VER_DAY 18
#define PDC_VER_DAY 21

#define PDC_STRINGIZE( x) #x
#define PDC_stringize( x) PDC_STRINGIZE( x)
Expand Down
11 changes: 11 additions & 0 deletions fb/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,17 @@ LINK = $(CC)
LDFLAGS = $(LIBCURSES)
RANLIB = ranlib

ifeq ($(DRM),Y)
CFLAGS += -DUSE_DRM -I /usr/include/drm
LDFLAGS += -ldrm
endif

ifeq ($(shell uname -s),FreeBSD)
CC = cc
CFLAGS += -DUSE_DRM -I/usr/local/include -I/usr/local/include/libdrm
LDFLAGS += -L /usr/local/lib -ldrm
endif

.PHONY: all libs clean demos

all: libs
Expand Down
254 changes: 254 additions & 0 deletions fb/drm.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
/* DRM (Direct Rendering Manager, _not_ Digital Restrictions or Rights
Management!) functions. */

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>

#include <sys/ioctl.h>
#include <sys/mman.h>

#ifdef __linux__
#include <drm/drm.h>
#include <drm/drm_mode.h>
#else
#include <libdrm/drm.h>
#include <libdrm/drm_mode.h>
#endif

#include <xf86drm.h>
#include <xf86drmMode.h>

struct type_name {
unsigned int type;
const char *name;
};

struct framebuffer {
int fd;
uint32_t buffer_id;
uint16_t res_x;
uint16_t res_y;
uint8_t *data;
uint32_t size;
struct drm_mode_create_dumb dumb_framebuffer;
drmModeCrtcPtr crtc;
drmModeConnectorPtr connector;
drmModeModeInfoPtr resolution;
};

static const struct type_name connector_type_names[] = {
{ DRM_MODE_CONNECTOR_Unknown, "unknown" },
{ DRM_MODE_CONNECTOR_VGA, "VGA" },
{ DRM_MODE_CONNECTOR_DVII, "DVI-I" },
{ DRM_MODE_CONNECTOR_DVID, "DVI-D" },
{ DRM_MODE_CONNECTOR_DVIA, "DVI-A" },
{ DRM_MODE_CONNECTOR_Composite, "composite" },
{ DRM_MODE_CONNECTOR_SVIDEO, "s-video" },
{ DRM_MODE_CONNECTOR_LVDS, "LVDS" },
{ DRM_MODE_CONNECTOR_Component, "component" },
{ DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" },
{ DRM_MODE_CONNECTOR_DisplayPort, "DP" },
{ DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" },
{ DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" },
{ DRM_MODE_CONNECTOR_TV, "TV" },
{ DRM_MODE_CONNECTOR_eDP, "eDP" },
{ DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" },
{ DRM_MODE_CONNECTOR_DSI, "DSI" },
{ DRM_MODE_CONNECTOR_DPI, "DPI" },
};

#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))

const char *connector_type_name(unsigned int type)
{
if (type < ARRAY_SIZE(connector_type_names)) {
return connector_type_names[type].name;
}

return "INVALID";
}

void release_framebuffer(struct framebuffer *fb)
{
if (fb->fd) {
/* Try to become master again, else we can't set CRTC. Then the current master needs to reset everything. */
drmSetMaster(fb->fd);
if (fb->crtc) {
/* Set back to orignal frame buffer */
drmModeSetCrtc(fb->fd, fb->crtc->crtc_id, fb->crtc->buffer_id, 0, 0, &fb->connector->connector_id, 1, fb->resolution);
drmModeFreeCrtc(fb->crtc);
}
if (fb->buffer_id)
drmModeFreeFB(drmModeGetFB(fb->fd, fb->buffer_id));
/* This will also release resolution */
if (fb->connector) {
drmModeFreeConnector(fb->connector);
fb->resolution = 0;
}
// if (fb->dumb_framebuffer.handle)
// ioctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, fb->dumb_framebuffer);
close(fb->fd);
}
}

#define FRAMEBUFFER_COULD_NOT_OPEN_DEVICE -1
#define FRAMEBUFFER_COULD_NOT_GET_RESOURCES -2
#define FRAMEBUFFER_COULD_NOT_FIND_CONNECTOR -3
#define FRAMEBUFFER_COULD_NOT_FIND_RESOLUTION -4
#define FRAMEBUFFER_COULD_NOT_CREATE_FRAMEBUFFER -5
#define FRAMEBUFFER_COULD_NOT_ADD_FRAMEBUFFER_TO_DRM -6
#define FRAMEBUFFER_COULD_NOT_GET_ENCODER -7
#define FRAMEBUFFER_MODE_MAP_FRAMEBUFFER_FAILED -8
#define FRAMEBUFFER_MODE_MAP_FAILED -9

int get_framebuffer(const char *dri_device, const char *connector_name, struct framebuffer *fb)
{
int err;
int fd;
drmModeResPtr res;
drmModeEncoderPtr encoder = 0;

/* Open the dri device /dev/dri/cardX */
fd = open(dri_device, O_RDWR);
if (fd < 0)
return FRAMEBUFFER_COULD_NOT_OPEN_DEVICE;

/* Get the resources of the DRM device (connectors, encoders, etc.)*/
res = drmModeGetResources(fd);
if (!res) {
close( fd);
return FRAMEBUFFER_COULD_NOT_GET_RESOURCES;
}

/* Search the connector provided as argument */
drmModeConnectorPtr connector = 0;
for (int i = 0; i < res->count_connectors; i++) {
char name[32];

connector = drmModeGetConnectorCurrent(fd, res->connectors[i]);
if (!connector)
continue;

snprintf(name, sizeof(name), "%s-%u", connector_type_name(connector->connector_type),
connector->connector_type_id);

if (strncmp(name, connector_name, sizeof(name)) == 0)
break;

if (strcmp( "def", connector_name) == 0 && connector->count_modes)
break;

drmModeFreeConnector(connector);
}
drmModeFreeResources( res);

if (!connector)
return FRAMEBUFFER_COULD_NOT_FIND_CONNECTOR;

/* Get the preferred resolution */
drmModeModeInfoPtr resolution = 0;
for (int i = 0; i < connector->count_modes; i++) {
resolution = &connector->modes[i];
if (resolution->type & DRM_MODE_TYPE_PREFERRED)
break;
}

if (!resolution) {
err = FRAMEBUFFER_COULD_NOT_FIND_RESOLUTION;
goto cleanup;
}

fb->dumb_framebuffer.height = resolution->vdisplay;
fb->dumb_framebuffer.width = resolution->hdisplay;
fb->dumb_framebuffer.bpp = 32;

err = ioctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &fb->dumb_framebuffer);
if (err) {
err = FRAMEBUFFER_COULD_NOT_CREATE_FRAMEBUFFER;
goto cleanup;
}

err = drmModeAddFB(fd, resolution->hdisplay, resolution->vdisplay, 24, 32,
fb->dumb_framebuffer.pitch, fb->dumb_framebuffer.handle, &fb->buffer_id);
if (err) {
err = FRAMEBUFFER_COULD_NOT_ADD_FRAMEBUFFER_TO_DRM;
goto cleanup;
}

encoder = drmModeGetEncoder(fd, connector->encoder_id);
if (!encoder) {
err = FRAMEBUFFER_COULD_NOT_GET_ENCODER;
goto cleanup;
}

/* Get the crtc settings */
fb->crtc = drmModeGetCrtc(fd, encoder->crtc_id);

struct drm_mode_map_dumb mreq;

memset(&mreq, 0, sizeof(mreq));
mreq.handle = fb->dumb_framebuffer.handle;

err = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);
if (err) {
err = FRAMEBUFFER_MODE_MAP_FRAMEBUFFER_FAILED;
goto cleanup;
}

fb->data = mmap(0, fb->dumb_framebuffer.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, mreq.offset);
if (fb->data == MAP_FAILED) {
err = FRAMEBUFFER_MODE_MAP_FAILED;
goto cleanup;
}

/* Make sure we are not master anymore so that other processes can add new framebuffers as well */
drmDropMaster(fd);

fb->fd = fd;
fb->connector = connector;
fb->resolution = resolution;

cleanup:
/* We don't need the encoder and connector anymore so let's free them */
if (encoder)
drmModeFreeEncoder(encoder);

if (err)
release_framebuffer(fb);

return err;
}

/* Interface between DRM functions above and PDCursesMod */

static struct framebuffer _drm_framebuffer;

static int init_drm( const char *dri_device, const char *connector_name)
{
int rval = get_framebuffer( dri_device, connector_name, &_drm_framebuffer);

if( !rval)
{
PDC_fb.framebuf = _drm_framebuffer.data;
PDC_fb.xres = _drm_framebuffer.dumb_framebuffer.width;
PDC_fb.yres = _drm_framebuffer.dumb_framebuffer.height;
PDC_fb.bits_per_pixel = 32;
PDC_fb.line_length = _drm_framebuffer.dumb_framebuffer.width;
PDC_fb.line_length *= sizeof( uint32_t);
PDC_fb.smem_len = 0; /* unused */
drmSetMaster(_drm_framebuffer.fd);
drmModeSetCrtc( _drm_framebuffer.fd, _drm_framebuffer.crtc->crtc_id, 0, 0, 0, NULL, 0, NULL);
drmModeSetCrtc( _drm_framebuffer.fd, _drm_framebuffer.crtc->crtc_id, _drm_framebuffer.buffer_id, 0, 0, &_drm_framebuffer.connector->connector_id, 1, _drm_framebuffer.resolution);
drmDropMaster(_drm_framebuffer.fd);
}
return( rval);
}

static void close_drm( void)
{
release_framebuffer( &_drm_framebuffer);
}
33 changes: 15 additions & 18 deletions fb/pdcdisp.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <linux/fb.h>
#include <sys/time.h>
#include <unistd.h>

Expand Down Expand Up @@ -183,29 +182,27 @@ static const uint8_t *_get_raw_glyph_bytes( struct font_info *font, int unicode_
return( font->glyphs + glyph_idx * font_char_size_in_bytes * font->height);
}

extern struct fb_fix_screeninfo PDC_finfo;
extern struct fb_var_screeninfo PDC_vinfo;
extern uint8_t *PDC_framebuf;
extern struct font_info PDC_font_info;
extern struct video_info PDC_fb;

void PDC_draw_rectangle( const int xpix, const int ypix,
const int xsize, const int ysize, const uint32_t color)
{
const int line_len = PDC_finfo.line_length * 8 / PDC_vinfo.bits_per_pixel;
const int line_len = PDC_fb.line_length * 8 / PDC_fb.bits_per_pixel;
int x, y;
const long video_offset = xpix + ypix * line_len;

if( PDC_vinfo.bits_per_pixel == 32)
if( PDC_fb.bits_per_pixel == 32)
{
uint32_t *tptr = (uint32_t *)PDC_framebuf + video_offset;
uint32_t *tptr = (uint32_t *)PDC_fb.framebuf + video_offset;

for( y = ysize; y; y--, tptr += line_len - xsize)
for( x = xsize; x; x--)
*tptr++ = color;
}
if( PDC_vinfo.bits_per_pixel == 8)
if( PDC_fb.bits_per_pixel == 8)
{
uint8_t *tptr = PDC_framebuf + video_offset;
uint8_t *tptr = (uint8_t *)PDC_fb.framebuf + video_offset;

for( y = ysize; y; y--, tptr += line_len - xsize)
for( x = xsize; x; x--)
Expand Down Expand Up @@ -338,7 +335,7 @@ void PDC_transform_line(int lineno, int x, int len, const chtype *srcp)
{
const int font_char_size_in_bytes = (PDC_font_info.width + 7) >> 3;
int cursor_to_draw = 0;
const int line_len = PDC_finfo.line_length * 8 / PDC_vinfo.bits_per_pixel;
const int line_len = PDC_fb.line_length * 8 / PDC_fb.bits_per_pixel;
uint8_t scratch[300];

assert( srcp);
Expand All @@ -347,11 +344,11 @@ void PDC_transform_line(int lineno, int x, int len, const chtype *srcp)
assert( lineno >= 0);
assert( lineno < SP->lines);
assert( len > 0);
if( lineno > (int)( PDC_vinfo.yres / PDC_font_info.height))
if( lineno > (int)( PDC_fb.yres / PDC_font_info.height))
return;
if( x + len > (int)( PDC_vinfo.xres / PDC_font_info.width))
if( x + len > (int)( PDC_fb.xres / PDC_font_info.width))
{
len = (int)( PDC_vinfo.xres / PDC_font_info.width) - x;
len = (int)( PDC_fb.xres / PDC_font_info.width) - x;
if( len <= 0)
return;
}
Expand Down Expand Up @@ -393,10 +390,10 @@ void PDC_transform_line(int lineno, int x, int len, const chtype *srcp)
}
while( run_len < len && !((*srcp ^ srcp[run_len]) & A_ATTRIBUTES))
run_len++;
if( PDC_vinfo.bits_per_pixel == 32)
if( PDC_fb.bits_per_pixel == 32)
{
int i;
uint32_t *tptr = (uint32_t *)PDC_framebuf + video_offset;
uint32_t *tptr = (uint32_t *)PDC_fb.framebuf + video_offset;

for( i = 0; i < run_len; i++)
{
Expand All @@ -417,12 +414,12 @@ void PDC_transform_line(int lineno, int x, int len, const chtype *srcp)
x++;
}
}
if( PDC_vinfo.bits_per_pixel == 8)
if( PDC_fb.bits_per_pixel == 8)
{
const int line_len = PDC_finfo.line_length; /* / sizeof( uint8_t); */
const int line_len = PDC_fb.line_length; /* / sizeof( uint8_t); */
int i, integer_fg_idx, integer_bg_idx;
uint8_t fg_idx, bg_idx;
uint8_t *tptr = PDC_framebuf + video_offset;
uint8_t *tptr = (uint8_t *)PDC_fb.framebuf + video_offset;
bool reverse_colors = ((*srcp & A_REVERSE) ? TRUE : FALSE);

extended_pair_content( (*srcp & A_COLOR) >> PDC_COLOR_SHIFT,
Expand Down
8 changes: 8 additions & 0 deletions fb/pdcfb.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,11 @@
#endif

void PDC_puts_to_stdout( const char *buff); /* pdcdisp.c */

struct video_info
{
void *framebuf;
unsigned xres, yres, bits_per_pixel;
unsigned line_length;
unsigned smem_len;
};
Loading

0 comments on commit e9bc09c

Please sign in to comment.