glcd driver: Add direct support for framebuffer with paged memory layout.

'struct glcd_framebuf' now contains a layout type which can either be
FB_TYPE_LINEAR (this is the default) or FB_TYPE_VPAGED. This actually affects
the drawing function and the frame-buffer memory calculation. A new 'size'
field is added to store the pre-calculated length.

Adopt existing driver to make use of the new feature (currently only glcd2usb
driver).
This commit is contained in:
mmdolze
2013-01-17 21:44:30 +00:00
parent 2f8df7fb35
commit 37563b5fd7
7 changed files with 91 additions and 77 deletions
+1
View File
@@ -9,6 +9,7 @@ v0.5dev (ongoing development)
* Fix using the left key to change the ring and checkbox menu items * Fix using the left key to change the ring and checkbox menu items
* sed1520: Add an option for inverted segment mapping (idea by R. Buchert) * sed1520: Add an option for inverted segment mapping (idea by R. Buchert)
* Fix build if compiled with --enable-permissive-menu-goto (#3599609) * Fix build if compiled with --enable-permissive-menu-goto (#3599609)
* glcd driver: Add direct support for framebuffer with paged memory layout
v0.5.6 v0.5.6
- Remove deprecated CFontz633 driver. Use CFontzPacket with Model=633 instead! - Remove deprecated CFontz633 driver. Use CFontzPacket with Model=633 instead!
+27 -43
View File
@@ -33,10 +33,6 @@
#define GLCD2USB_VID 0x1c40 #define GLCD2USB_VID 0x1c40
#define GLCD2USB_PID 0x0525 #define GLCD2USB_PID 0x0525
/* Some useful shortcuts */
#define PAGES (p->framebuf.px_height / 8)
#define PAGED_SIZE (p->framebuf.px_width * PAGES)
/** Data local to the glcd2usb connection type */ /** Data local to the glcd2usb connection type */
typedef struct glcd_glcd2usb_data { typedef struct glcd_glcd2usb_data {
usb_dev_handle *device; usb_dev_handle *device;
@@ -229,37 +225,25 @@ void
glcd2usb_blit(PrivateData *p) glcd2usb_blit(PrivateData *p)
{ {
CT_glcd2usb_data *ctd = (CT_glcd2usb_data *) p->ct_data; CT_glcd2usb_data *ctd = (CT_glcd2usb_data *) p->ct_data;
int c, r; int r;
int i, j; int i, j;
int err; int err;
int pos;
p->glcd_functions->drv_debug(RPT_DEBUG, "glcd2usb_blit: starting"); p->glcd_functions->drv_debug(RPT_DEBUG, "glcd2usb_blit: starting");
/* Reset the dirty buffer */ /* Reset the dirty buffer */
memset(ctd->dirty_buffer, 0x00, PAGED_SIZE); memset(ctd->dirty_buffer, 0x00, p->framebuf.size);
/* /*
* Step 1: Convert the linear frame buffer format of the glcd driver * Step 1: Compare the content of the secondary buffer with the frame
* into the paged format of the glcd2usb device. Compare newly * buffer and copy the differences. For each different byte, set the
* written data with what was stored previously and set the dirty * flag in the dirty buffer.
* buffer.
*/ */
for (r = 0; r < p->framebuf.px_height; r++) { for (pos = 0; pos < p->framebuf.size; pos++) {
int position, bit; if (ctd->paged_buffer[pos] != p->framebuf.data[pos]) {
unsigned char tmp; ctd->paged_buffer[pos] = p->framebuf.data[pos];
for (c = 0; c < p->framebuf.px_width; c++) { ctd->dirty_buffer[pos] = 1;
position = (r / 8) * p->framebuf.px_width + c;
bit = r % 8;
tmp = ctd->paged_buffer[position];
if (fb_get_pixel(&(p->framebuf), c, r) == FB_BLACK)
ctd->paged_buffer[position] |= 1 << bit;
else
ctd->paged_buffer[position] &= ~(1 << bit);
if (ctd->paged_buffer[position] != tmp)
ctd->dirty_buffer[position] = 1;
} }
} }
@@ -267,7 +251,7 @@ glcd2usb_blit(PrivateData *p)
* Step 2: Short gaps of unchanged bytes in fact increase the * Step 2: Short gaps of unchanged bytes in fact increase the
* communication overhead. So we eliminate them here. * communication overhead. So we eliminate them here.
*/ */
for (j = -1, i = 0; i < PAGED_SIZE; i++) { for (j = -1, i = 0; i < p->framebuf.size; i++) {
if (ctd->dirty_buffer[i] && j >= 0 && i - j <= 4) { if (ctd->dirty_buffer[i] && j >= 0 && i - j <= 4) {
/* found a clean gap <= 4 bytes: mark it dirty */ /* found a clean gap <= 4 bytes: mark it dirty */
for (r = j; r < i; r++) for (r = j; r < i; r++)
@@ -285,7 +269,7 @@ glcd2usb_blit(PrivateData *p)
/* Step 3: Send the changes. */ /* Step 3: Send the changes. */
ctd->tx_buffer.bytes[0] = 0; ctd->tx_buffer.bytes[0] = 0;
for (i = 0; i < PAGED_SIZE; i++) { for (i = 0; i < p->framebuf.size; i++) {
if (ctd->dirty_buffer[i]) { if (ctd->dirty_buffer[i]) {
/* Start a new packet */ /* Start a new packet */
if (!ctd->tx_buffer.bytes[0]) { if (!ctd->tx_buffer.bytes[0]) {
@@ -303,7 +287,7 @@ glcd2usb_blit(PrivateData *p)
* the frame or reached the maximum payload for a write * the frame or reached the maximum payload for a write
* request. * request.
*/ */
if (!ctd->dirty_buffer[i] || i == PAGED_SIZE - 1 || ctd->tx_buffer.bytes[3] == 128) { if (!ctd->dirty_buffer[i] || i == p->framebuf.size - 1 || ctd->tx_buffer.bytes[3] == 128) {
/* Only write if there IS something to be written */ /* Only write if there IS something to be written */
if (ctd->tx_buffer.bytes[0] == GLCD2USB_RID_WRITE && ctd->tx_buffer.bytes[3] > 0) { if (ctd->tx_buffer.bytes[0] == GLCD2USB_RID_WRITE && ctd->tx_buffer.bytes[3] > 0) {
err = usbSetReport(ctd->device, USB_HID_REPORT_TYPE_FEATURE, err = usbSetReport(ctd->device, USB_HID_REPORT_TYPE_FEATURE,
@@ -380,19 +364,6 @@ glcd2usb_init(Driver *drvthis)
} }
p->ct_data = ctd; p->ct_data = ctd;
ctd->paged_buffer = malloc(PAGED_SIZE);
if (ctd->paged_buffer == NULL) {
report(RPT_ERR, "%s/glcd2usb: cannot allocate memory", drvthis->name);
goto err_out;
}
memset(ctd->paged_buffer, 0x00, PAGED_SIZE);
ctd->dirty_buffer = malloc(PAGED_SIZE);
if (ctd->dirty_buffer == NULL) {
report(RPT_ERR, "%s/glcd2usb: cannot allocate memory", drvthis->name);
goto err_out;
}
/* /*
* Try to find and open a device. Only the first device found will be * Try to find and open a device. Only the first device found will be
* recognized. * recognized.
@@ -488,11 +459,24 @@ found_dev:
ctd->tx_buffer.display_info.height); ctd->tx_buffer.display_info.height);
goto err_out; goto err_out;
} }
else { p->framebuf.layout = FB_TYPE_VPAGED;
p->framebuf.px_width = ctd->tx_buffer.display_info.width; p->framebuf.px_width = ctd->tx_buffer.display_info.width;
p->framebuf.px_height = ctd->tx_buffer.display_info.height; p->framebuf.px_height = ctd->tx_buffer.display_info.height;
p->framebuf.size = (p->framebuf.px_height + 7) / 8 * p->framebuf.px_width;
report(RPT_INFO, "%s/glcd2usb: using display size %dx%d", drvthis->name, report(RPT_INFO, "%s/glcd2usb: using display size %dx%d", drvthis->name,
ctd->tx_buffer.display_info.width, ctd->tx_buffer.display_info.height); ctd->tx_buffer.display_info.width, ctd->tx_buffer.display_info.height);
ctd->paged_buffer = malloc(p->framebuf.size);
if (ctd->paged_buffer == NULL) {
report(RPT_ERR, "%s/glcd2usb: cannot allocate memory", drvthis->name);
goto err_out;
}
memset(ctd->paged_buffer, 0x55, p->framebuf.size);
ctd->dirty_buffer = malloc(p->framebuf.size);
if (ctd->dirty_buffer == NULL) {
report(RPT_ERR, "%s/glcd2usb: cannot allocate memory", drvthis->name);
goto err_out;
} }
/* Allocate the display (turn off the 'whirl') */ /* Allocate the display (turn off the 'whirl') */
+19 -2
View File
@@ -20,12 +20,19 @@
#define GLCD_DEFAULT_REPEAT_DELAY 500 /* milliseconds */ #define GLCD_DEFAULT_REPEAT_DELAY 500 /* milliseconds */
#define GLCD_DEFAULT_REPEAT_INTERVAL 300 /* milliseconds */ #define GLCD_DEFAULT_REPEAT_INTERVAL 300 /* milliseconds */
enum fb_types {
FB_TYPE_LINEAR = 0,
FB_TYPE_VPAGED
};
/** The framebuffer and its properties */ /** The framebuffer and its properties */
struct glcd_framebuf { struct glcd_framebuf {
unsigned char *data; /**< frame buffer */ unsigned char *data; /**< frame buffer */
int px_width; /**< display width in dots */ int px_width; /**< display width in dots */
int px_height; /**< display height in dots */ int px_height; /**< display height in dots */
int bytesPerLine; /**< number of bytes per pixel row */ int bytesPerLine; /**< number of bytes per pixel row */
int size; /**< total size in bytes */
enum fb_types layout; /**< memory layout */
}; };
/** private data for the \c glcd driver */ /** private data for the \c glcd driver */
@@ -82,8 +89,6 @@ struct glcdHwFcns {
/* ================== Framebuffer functions and macros =================== */ /* ================== Framebuffer functions and macros =================== */
#define BYTES_PER_LINE (p->framebuf.bytesPerLine)
#define FB_BYTES_TOTAL (p->framebuf.px_height * BYTES_PER_LINE)
#define FB_BLACK 1 #define FB_BLACK 1
#define FB_WHITE 0 #define FB_WHITE 0
@@ -106,8 +111,14 @@ fb_draw_pixel(struct glcd_framebuf *fb, int x, int y, int color)
if (x < 0 || x >= fb->px_width || y < 0 || y >= fb->px_height) if (x < 0 || x >= fb->px_width || y < 0 || y >= fb->px_height)
return; return;
if (fb->layout == FB_TYPE_LINEAR) {
pos = y * fb->bytesPerLine + (x / 8); pos = y * fb->bytesPerLine + (x / 8);
bit = 0x80 >> (x % 8); bit = 0x80 >> (x % 8);
}
else {
pos = (y / 8) * fb->px_width + x;
bit = 1 << (y % 8);
}
if (color == FB_BLACK) if (color == FB_BLACK)
fb->data[pos] |= bit; fb->data[pos] |= bit;
@@ -133,8 +144,14 @@ fb_get_pixel(struct glcd_framebuf *fb, int x, int y)
if (x < 0 || x >= fb->px_width || y < 0 || y >= fb->px_height) if (x < 0 || x >= fb->px_width || y < 0 || y >= fb->px_height)
return FB_WHITE; return FB_WHITE;
if (fb->layout == FB_TYPE_LINEAR) {
pos = y * fb->bytesPerLine + (x / 8); pos = y * fb->bytesPerLine + (x / 8);
bit = 0x80 >> (x % 8); bit = 0x80 >> (x % 8);
}
else {
pos = (y / 8) * fb->px_width + x;
bit = 0x01 << (y % 8);
}
if (fb->data[pos] & bit) if (fb->data[pos] & bit)
return FB_BLACK; return FB_BLACK;
+5 -5
View File
@@ -63,12 +63,12 @@ glcd_png_init(Driver *drvthis)
} }
p->ct_data = ct_data; p->ct_data = ct_data;
ct_data->backingstore = malloc(FB_BYTES_TOTAL); ct_data->backingstore = malloc(p->framebuf.size);
if (ct_data->backingstore == NULL) { if (ct_data->backingstore == NULL) {
report(RPT_ERR, "GLCD/png: unable to allocate backing store"); report(RPT_ERR, "GLCD/png: unable to allocate backing store");
return -1; return -1;
} }
memset(ct_data->backingstore, 0x00, FB_BYTES_TOTAL); memset(ct_data->backingstore, 0x00, p->framebuf.size);
debug(RPT_DEBUG, "GLCD/png: init() done"); debug(RPT_DEBUG, "GLCD/png: init() done");
@@ -92,7 +92,7 @@ glcd_png_blit(PrivateData *p)
png_bytep row_pointer; png_bytep row_pointer;
/* Check if framebufer has changed. If not there's nothing to do */ /* Check if framebufer has changed. If not there's nothing to do */
if (memcmp(p->framebuf.data, ct_data->backingstore, FB_BYTES_TOTAL) == 0) if (memcmp(p->framebuf.data, ct_data->backingstore, p->framebuf.size) == 0)
return; return;
snprintf(filename, sizeof(filename), "/tmp/lcdproc%06d.png", num++); snprintf(filename, sizeof(filename), "/tmp/lcdproc%06d.png", num++);
@@ -134,7 +134,7 @@ glcd_png_blit(PrivateData *p)
row_pointer = p->framebuf.data; row_pointer = p->framebuf.data;
for (row = 0; row < p->framebuf.px_height; row++) { for (row = 0; row < p->framebuf.px_height; row++) {
png_write_row(png_ptr, row_pointer); png_write_row(png_ptr, row_pointer);
row_pointer += BYTES_PER_LINE; row_pointer += p->framebuf.bytesPerLine;
} }
png_write_end(png_ptr, NULL); png_write_end(png_ptr, NULL);
@@ -142,7 +142,7 @@ glcd_png_blit(PrivateData *p)
fp = NULL; fp = NULL;
png_destroy_write_struct(&png_ptr, &info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr);
memcpy(ct_data->backingstore, p->framebuf.data, FB_BYTES_TOTAL); memcpy(ct_data->backingstore, p->framebuf.data, p->framebuf.size);
return; return;
+4 -2
View File
@@ -125,12 +125,14 @@ glcd_serdisp_init(Driver *drvthis)
ct_data->bsbuf.px_width = p->framebuf.px_width; ct_data->bsbuf.px_width = p->framebuf.px_width;
ct_data->bsbuf.px_height = p->framebuf.px_height; ct_data->bsbuf.px_height = p->framebuf.px_height;
ct_data->bsbuf.bytesPerLine = p->framebuf.bytesPerLine; ct_data->bsbuf.bytesPerLine = p->framebuf.bytesPerLine;
ct_data->bsbuf.data = malloc(ct_data->bsbuf.px_height * ct_data->bsbuf.bytesPerLine); ct_data->bsbuf.size = p->framebuf.size;
ct_data->bsbuf.data = malloc(ct_data->bsbuf.size);
if (ct_data->bsbuf.data == NULL) { if (ct_data->bsbuf.data == NULL) {
report(RPT_ERR, "%s: error allocating backing store", report(RPT_ERR, "%s: error allocating backing store",
drvthis->name); drvthis->name);
goto err_out;
} }
memset(ct_data->bsbuf.data, 0x00, ct_data->bsbuf.px_height * ct_data->bsbuf.bytesPerLine); memset(ct_data->bsbuf.data, 0x00, ct_data->bsbuf.size);
serdisp_clearbuffer(ct_data->disp); serdisp_clearbuffer(ct_data->disp);
+10 -10
View File
@@ -80,12 +80,12 @@ glcd_t6963_init(Driver *drvthis)
} }
ct_data->port_config = port_config; ct_data->port_config = port_config;
ct_data->backingstore = malloc(FB_BYTES_TOTAL); ct_data->backingstore = malloc(p->framebuf.size);
if (ct_data->backingstore == NULL) { if (ct_data->backingstore == NULL) {
report(RPT_ERR, "GLCD/T6963: unable to allocate backing store"); report(RPT_ERR, "GLCD/T6963: unable to allocate backing store");
return -1; return -1;
} }
memset(ct_data->backingstore, 0x00, FB_BYTES_TOTAL); memset(ct_data->backingstore, 0x00, p->framebuf.size);
/* Get port from config */ /* Get port from config */
port_config->port = drvthis->config_get_int(drvthis->name, "Port", 0, DEFAULT_PORT); port_config->port = drvthis->config_get_int(drvthis->name, "Port", 0, DEFAULT_PORT);
@@ -110,9 +110,9 @@ glcd_t6963_init(Driver *drvthis)
debug(RPT_INFO, "GLCD/T6963: Sending init to display..."); debug(RPT_INFO, "GLCD/T6963: Sending init to display...");
/* Set graphic address (and text address even though not needed) */ /* Set graphic address (and text address even though not needed) */
t6963_low_command_word(port_config, SET_GRAPHIC_HOME_ADDRESS, GRAPHIC_BASE); t6963_low_command_word(port_config, SET_GRAPHIC_HOME_ADDRESS, GRAPHIC_BASE);
t6963_low_command_word(port_config, SET_GRAPHIC_AREA, BYTES_PER_LINE); t6963_low_command_word(port_config, SET_GRAPHIC_AREA, p->framebuf.bytesPerLine);
t6963_low_command_word(port_config, SET_TEXT_HOME_ADDRESS, TEXT_BASE); t6963_low_command_word(port_config, SET_TEXT_HOME_ADDRESS, TEXT_BASE);
t6963_low_command_word(port_config, SET_TEXT_AREA, BYTES_PER_LINE); t6963_low_command_word(port_config, SET_TEXT_AREA, p->framebuf.bytesPerLine);
/* Use OR-mode for text and graphics */ /* Use OR-mode for text and graphics */
t6963_low_command(port_config, SET_MODE | OR_MODE); t6963_low_command(port_config, SET_MODE | OR_MODE);
@@ -139,12 +139,12 @@ glcd_t6963_blit(PrivateData *p)
for (y = 0; y < p->framebuf.px_height; y++) { for (y = 0; y < p->framebuf.px_height; y++) {
/* set pointers to start of the line */ /* set pointers to start of the line */
unsigned char *sp = p->framebuf.data + (y * BYTES_PER_LINE); unsigned char *sp = p->framebuf.data + (y * p->framebuf.bytesPerLine);
unsigned char *sq = ct_data->backingstore + (y * BYTES_PER_LINE); unsigned char *sq = ct_data->backingstore + (y * p->framebuf.bytesPerLine);
/* set pointers to end of the line */ /* set pointers to end of the line */
unsigned char *ep = sp + (BYTES_PER_LINE - 1); unsigned char *ep = sp + (p->framebuf.bytesPerLine - 1);
unsigned char *eq = sq + (BYTES_PER_LINE - 1); unsigned char *eq = sq + (p->framebuf.bytesPerLine - 1);
/* find begin and end of differences */ /* find begin and end of differences */
x = 0; x = 0;
@@ -158,7 +158,7 @@ glcd_t6963_blit(PrivateData *p)
/* there are differences, ... */ /* there are differences, ... */
if (sp <= ep) { if (sp <= ep) {
t6963_low_command_word(ct_data->port_config, SET_ADDRESS_POINTER, t6963_low_command_word(ct_data->port_config, SET_ADDRESS_POINTER,
GRAPHIC_BASE + (y * BYTES_PER_LINE) + x); GRAPHIC_BASE + (y * p->framebuf.bytesPerLine) + x);
t6963_low_command(ct_data->port_config, AUTO_WRITE); t6963_low_command(ct_data->port_config, AUTO_WRITE);
while (sp <= ep) { while (sp <= ep) {
t6963_low_auto_write(ct_data->port_config, *sp); t6963_low_auto_write(ct_data->port_config, *sp);
@@ -203,7 +203,7 @@ static void
t6963_graphic_clear(PrivateData *p) t6963_graphic_clear(PrivateData *p)
{ {
CT_t6963_data *ct_data = (CT_t6963_data *) p->ct_data; CT_t6963_data *ct_data = (CT_t6963_data *) p->ct_data;
int num = FB_BYTES_TOTAL; int num = p->framebuf.size;
int i; int i;
p->glcd_functions->drv_debug(RPT_DEBUG, "GLCD/T6963: Clearing graphic: %d bytes", num); p->glcd_functions->drv_debug(RPT_DEBUG, "GLCD/T6963: Clearing graphic: %d bytes", num);
+16 -6
View File
@@ -130,8 +130,10 @@ glcd_init(Driver *drvthis)
} }
p->framebuf.px_width = w; p->framebuf.px_width = w;
p->framebuf.px_height = h; p->framebuf.px_height = h;
p->framebuf.layout = FB_TYPE_LINEAR;
p->framebuf.bytesPerLine = (p->framebuf.px_width + 7) / 8; p->framebuf.bytesPerLine = (p->framebuf.px_width + 7) / 8;
debug(RPT_INFO, "%s: bytesPerLine (first) = %d", drvthis->name, BYTES_PER_LINE); p->framebuf.size = p->framebuf.bytesPerLine * p->framebuf.px_height;
debug(RPT_INFO, "%s: size (first) = %d", drvthis->name, p->framebuf.size);
/* Set contrast */ /* Set contrast */
tmp = drvthis->config_get_int(drvthis->name, "Contrast", 0, GLCD_DEFAULT_CONTRAST); tmp = drvthis->config_get_int(drvthis->name, "Contrast", 0, GLCD_DEFAULT_CONTRAST);
@@ -185,15 +187,23 @@ glcd_init(Driver *drvthis)
return -1; return -1;
} }
/* Allocate framebuffer (re-calculate bytesPerLine before) */ /* Allocate framebuffer (re-calculate size before) */
if (p->framebuf.layout == FB_TYPE_LINEAR) {
p->framebuf.bytesPerLine = (p->framebuf.px_width + 7) / 8; p->framebuf.bytesPerLine = (p->framebuf.px_width + 7) / 8;
debug(RPT_INFO, "%s: bytesPerLine (final) = %d", drvthis->name, BYTES_PER_LINE); p->framebuf.size = p->framebuf.bytesPerLine * p->framebuf.px_height;
p->framebuf.data = malloc(FB_BYTES_TOTAL); }
else {
p->framebuf.bytesPerLine = 0;
p->framebuf.size = (p->framebuf.px_height + 7) / 8 * p->framebuf.px_width;
}
debug(RPT_INFO, "%s: size (final) = %d", drvthis->name, p->framebuf.size);
p->framebuf.data = malloc(p->framebuf.size);
if (p->framebuf.data == NULL) { if (p->framebuf.data == NULL) {
report(RPT_ERR, "%s: unable to allocate framebuffer", drvthis->name); report(RPT_ERR, "%s: unable to allocate framebuffer", drvthis->name);
return -1; return -1;
} }
memset(p->framebuf.data, 0x00, FB_BYTES_TOTAL); memset(p->framebuf.data, 0x00, p->framebuf.size);
/* Initialize renderer */ /* Initialize renderer */
if (glcd_render_init(drvthis) != 0) if (glcd_render_init(drvthis) != 0)
@@ -356,7 +366,7 @@ glcd_clear(Driver *drvthis)
debug(RPT_DEBUG, "%s()", __FUNCTION__); debug(RPT_DEBUG, "%s()", __FUNCTION__);
memset(p->framebuf.data, 0x00, FB_BYTES_TOTAL); memset(p->framebuf.data, 0x00, p->framebuf.size);
} }