From 37563b5fd75c7eb16a8f9a07052a6fb6e28b1ac7 Mon Sep 17 00:00:00 2001 From: mmdolze Date: Thu, 17 Jan 2013 21:44:30 +0000 Subject: [PATCH] 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). --- ChangeLog | 1 + server/drivers/glcd-glcd2usb.c | 78 ++++++++++++++-------------------- server/drivers/glcd-low.h | 29 ++++++++++--- server/drivers/glcd-png.c | 10 ++--- server/drivers/glcd-serdisp.c | 6 ++- server/drivers/glcd-t6963.c | 20 ++++----- server/drivers/glcd_drv.c | 24 ++++++++--- 7 files changed, 91 insertions(+), 77 deletions(-) diff --git a/ChangeLog b/ChangeLog index f650b6d..5f7cee2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,6 +9,7 @@ v0.5dev (ongoing development) * 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) * Fix build if compiled with --enable-permissive-menu-goto (#3599609) + * glcd driver: Add direct support for framebuffer with paged memory layout v0.5.6 - Remove deprecated CFontz633 driver. Use CFontzPacket with Model=633 instead! diff --git a/server/drivers/glcd-glcd2usb.c b/server/drivers/glcd-glcd2usb.c index d403736..a2d19f7 100644 --- a/server/drivers/glcd-glcd2usb.c +++ b/server/drivers/glcd-glcd2usb.c @@ -33,10 +33,6 @@ #define GLCD2USB_VID 0x1c40 #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 */ typedef struct glcd_glcd2usb_data { usb_dev_handle *device; @@ -229,37 +225,25 @@ void glcd2usb_blit(PrivateData *p) { CT_glcd2usb_data *ctd = (CT_glcd2usb_data *) p->ct_data; - int c, r; + int r; int i, j; int err; + int pos; p->glcd_functions->drv_debug(RPT_DEBUG, "glcd2usb_blit: starting"); /* 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 - * into the paged format of the glcd2usb device. Compare newly - * written data with what was stored previously and set the dirty - * buffer. + * Step 1: Compare the content of the secondary buffer with the frame + * buffer and copy the differences. For each different byte, set the + * flag in the dirty buffer. */ - for (r = 0; r < p->framebuf.px_height; r++) { - int position, bit; - unsigned char tmp; - for (c = 0; c < p->framebuf.px_width; c++) { - 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; + for (pos = 0; pos < p->framebuf.size; pos++) { + if (ctd->paged_buffer[pos] != p->framebuf.data[pos]) { + ctd->paged_buffer[pos] = p->framebuf.data[pos]; + ctd->dirty_buffer[pos] = 1; } } @@ -267,7 +251,7 @@ glcd2usb_blit(PrivateData *p) * Step 2: Short gaps of unchanged bytes in fact increase the * 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) { /* found a clean gap <= 4 bytes: mark it dirty */ for (r = j; r < i; r++) @@ -285,7 +269,7 @@ glcd2usb_blit(PrivateData *p) /* Step 3: Send the changes. */ 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]) { /* Start a new packet */ if (!ctd->tx_buffer.bytes[0]) { @@ -303,7 +287,7 @@ glcd2usb_blit(PrivateData *p) * the frame or reached the maximum payload for a write * 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 */ if (ctd->tx_buffer.bytes[0] == GLCD2USB_RID_WRITE && ctd->tx_buffer.bytes[3] > 0) { err = usbSetReport(ctd->device, USB_HID_REPORT_TYPE_FEATURE, @@ -380,19 +364,6 @@ glcd2usb_init(Driver *drvthis) } 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 * recognized. @@ -488,11 +459,24 @@ found_dev: ctd->tx_buffer.display_info.height); goto err_out; } - else { - p->framebuf.px_width = ctd->tx_buffer.display_info.width; - p->framebuf.px_height = ctd->tx_buffer.display_info.height; - report(RPT_INFO, "%s/glcd2usb: using display size %dx%d", drvthis->name, - ctd->tx_buffer.display_info.width, ctd->tx_buffer.display_info.height); + p->framebuf.layout = FB_TYPE_VPAGED; + p->framebuf.px_width = ctd->tx_buffer.display_info.width; + 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, + 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') */ diff --git a/server/drivers/glcd-low.h b/server/drivers/glcd-low.h index 240f7ab..cf7ad7f 100644 --- a/server/drivers/glcd-low.h +++ b/server/drivers/glcd-low.h @@ -20,12 +20,19 @@ #define GLCD_DEFAULT_REPEAT_DELAY 500 /* milliseconds */ #define GLCD_DEFAULT_REPEAT_INTERVAL 300 /* milliseconds */ +enum fb_types { + FB_TYPE_LINEAR = 0, + FB_TYPE_VPAGED +}; + /** The framebuffer and its properties */ struct glcd_framebuf { unsigned char *data; /**< frame buffer */ int px_width; /**< display width in dots */ int px_height; /**< display height in dots */ 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 */ @@ -82,8 +89,6 @@ struct glcdHwFcns { /* ================== 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_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) return; - pos = y * fb->bytesPerLine + (x / 8); - bit = 0x80 >> (x % 8); + if (fb->layout == FB_TYPE_LINEAR) { + pos = y * fb->bytesPerLine + (x / 8); + bit = 0x80 >> (x % 8); + } + else { + pos = (y / 8) * fb->px_width + x; + bit = 1 << (y % 8); + } if (color == FB_BLACK) 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) return FB_WHITE; - pos = y * fb->bytesPerLine + (x / 8); - bit = 0x80 >> (x % 8); + if (fb->layout == FB_TYPE_LINEAR) { + pos = y * fb->bytesPerLine + (x / 8); + bit = 0x80 >> (x % 8); + } + else { + pos = (y / 8) * fb->px_width + x; + bit = 0x01 << (y % 8); + } if (fb->data[pos] & bit) return FB_BLACK; diff --git a/server/drivers/glcd-png.c b/server/drivers/glcd-png.c index 35edab3..c0e3e83 100644 --- a/server/drivers/glcd-png.c +++ b/server/drivers/glcd-png.c @@ -63,12 +63,12 @@ glcd_png_init(Driver *drvthis) } p->ct_data = ct_data; - ct_data->backingstore = malloc(FB_BYTES_TOTAL); + ct_data->backingstore = malloc(p->framebuf.size); if (ct_data->backingstore == NULL) { report(RPT_ERR, "GLCD/png: unable to allocate backing store"); 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"); @@ -92,7 +92,7 @@ glcd_png_blit(PrivateData *p) png_bytep row_pointer; /* 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; snprintf(filename, sizeof(filename), "/tmp/lcdproc%06d.png", num++); @@ -134,7 +134,7 @@ glcd_png_blit(PrivateData *p) row_pointer = p->framebuf.data; for (row = 0; row < p->framebuf.px_height; row++) { png_write_row(png_ptr, row_pointer); - row_pointer += BYTES_PER_LINE; + row_pointer += p->framebuf.bytesPerLine; } png_write_end(png_ptr, NULL); @@ -142,7 +142,7 @@ glcd_png_blit(PrivateData *p) fp = NULL; 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; diff --git a/server/drivers/glcd-serdisp.c b/server/drivers/glcd-serdisp.c index a90cb90..751d22d 100644 --- a/server/drivers/glcd-serdisp.c +++ b/server/drivers/glcd-serdisp.c @@ -125,12 +125,14 @@ glcd_serdisp_init(Driver *drvthis) ct_data->bsbuf.px_width = p->framebuf.px_width; ct_data->bsbuf.px_height = p->framebuf.px_height; 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) { report(RPT_ERR, "%s: error allocating backing store", 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); diff --git a/server/drivers/glcd-t6963.c b/server/drivers/glcd-t6963.c index 130637e..11e5cff 100644 --- a/server/drivers/glcd-t6963.c +++ b/server/drivers/glcd-t6963.c @@ -80,12 +80,12 @@ glcd_t6963_init(Driver *drvthis) } 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) { report(RPT_ERR, "GLCD/T6963: unable to allocate backing store"); return -1; } - memset(ct_data->backingstore, 0x00, FB_BYTES_TOTAL); + memset(ct_data->backingstore, 0x00, p->framebuf.size); /* Get port from config */ 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..."); /* 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_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_AREA, BYTES_PER_LINE); + t6963_low_command_word(port_config, SET_TEXT_AREA, p->framebuf.bytesPerLine); /* Use OR-mode for text and graphics */ 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++) { /* set pointers to start of the line */ - unsigned char *sp = p->framebuf.data + (y * BYTES_PER_LINE); - unsigned char *sq = ct_data->backingstore + (y * BYTES_PER_LINE); + unsigned char *sp = p->framebuf.data + (y * p->framebuf.bytesPerLine); + unsigned char *sq = ct_data->backingstore + (y * p->framebuf.bytesPerLine); /* set pointers to end of the line */ - unsigned char *ep = sp + (BYTES_PER_LINE - 1); - unsigned char *eq = sq + (BYTES_PER_LINE - 1); + unsigned char *ep = sp + (p->framebuf.bytesPerLine - 1); + unsigned char *eq = sq + (p->framebuf.bytesPerLine - 1); /* find begin and end of differences */ x = 0; @@ -158,7 +158,7 @@ glcd_t6963_blit(PrivateData *p) /* there are differences, ... */ if (sp <= ep) { 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); while (sp <= ep) { t6963_low_auto_write(ct_data->port_config, *sp); @@ -203,7 +203,7 @@ static void t6963_graphic_clear(PrivateData *p) { CT_t6963_data *ct_data = (CT_t6963_data *) p->ct_data; - int num = FB_BYTES_TOTAL; + int num = p->framebuf.size; int i; p->glcd_functions->drv_debug(RPT_DEBUG, "GLCD/T6963: Clearing graphic: %d bytes", num); diff --git a/server/drivers/glcd_drv.c b/server/drivers/glcd_drv.c index b3d8978..64c58b2 100644 --- a/server/drivers/glcd_drv.c +++ b/server/drivers/glcd_drv.c @@ -130,8 +130,10 @@ glcd_init(Driver *drvthis) } p->framebuf.px_width = w; p->framebuf.px_height = h; + p->framebuf.layout = FB_TYPE_LINEAR; 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 */ tmp = drvthis->config_get_int(drvthis->name, "Contrast", 0, GLCD_DEFAULT_CONTRAST); @@ -185,15 +187,23 @@ glcd_init(Driver *drvthis) return -1; } - /* Allocate framebuffer (re-calculate bytesPerLine before) */ - p->framebuf.bytesPerLine = (p->framebuf.px_width + 7) / 8; - debug(RPT_INFO, "%s: bytesPerLine (final) = %d", drvthis->name, BYTES_PER_LINE); - p->framebuf.data = malloc(FB_BYTES_TOTAL); + /* Allocate framebuffer (re-calculate size before) */ + if (p->framebuf.layout == FB_TYPE_LINEAR) { + p->framebuf.bytesPerLine = (p->framebuf.px_width + 7) / 8; + p->framebuf.size = p->framebuf.bytesPerLine * p->framebuf.px_height; + } + 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) { report(RPT_ERR, "%s: unable to allocate framebuffer", drvthis->name); return -1; } - memset(p->framebuf.data, 0x00, FB_BYTES_TOTAL); + memset(p->framebuf.data, 0x00, p->framebuf.size); /* Initialize renderer */ if (glcd_render_init(drvthis) != 0) @@ -356,7 +366,7 @@ glcd_clear(Driver *drvthis) debug(RPT_DEBUG, "%s()", __FUNCTION__); - memset(p->framebuf.data, 0x00, FB_BYTES_TOTAL); + memset(p->framebuf.data, 0x00, p->framebuf.size); }