From 510987790902a17a2c4d5f33215d8e46b10eddd3 Mon Sep 17 00:00:00 2001 From: philippe44 Date: Tue, 25 Feb 2020 19:38:08 -0800 Subject: [PATCH] more display update (still need to fix ClearWindow) --- components/display/SH1106.c | 16 ++-- components/display/SSD1306.c | 16 ++-- components/display/SSD132x.c | 121 ++++++++++++++++++++++---- components/display/core/gds.c | 49 ++++++++--- components/display/core/gds_draw.c | 108 +++++++---------------- components/display/core/gds_draw.h | 2 +- components/display/core/gds_private.h | 3 +- components/display/display.c | 2 +- components/squeezelite/display.c | 13 ++- 9 files changed, 205 insertions(+), 125 deletions(-) diff --git a/components/display/SH1106.c b/components/display/SH1106.c index baba9c63..f6c1dc2f 100644 --- a/components/display/SH1106.c +++ b/components/display/SH1106.c @@ -80,19 +80,25 @@ static void SetContrast( struct GDS_Device* Device, uint8_t Contrast ) { static bool Init( struct GDS_Device* Device ) { Device->FramebufferSize = ( Device->Width * Device->Height ) / 8; + +// benchmarks showed little gain to have SPI memory already in IRAL vs letting driver copy +#ifdef SHADOW_BUFFER Device->Framebuffer = calloc( 1, Device->FramebufferSize ); NullCheck( Device->Framebuffer, return false ); - -#ifdef SHADOW_BUFFER #ifdef USE_IRAM - // benchmarks showed little gain to have SPI memory already in IRAL vs letting driver copy if (Device->IF == IF_SPI) Device->Shadowbuffer = heap_caps_malloc( Device->FramebufferSize, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA ); else -#else - Device->Shadowbuffer = malloc( Device->FramebufferSize ); #endif + Device->Shadowbuffer = malloc( Device->FramebufferSize ); NullCheck( Device->Shadowbuffer, return false ); memset(Device->Shadowbuffer, 0xFF, Device->FramebufferSize); +#else // not SHADOW_BUFFER +#ifdef USE_IRAM + // benchmarks showed little gain to have SPI memory already in IRAL vs letting driver copy + if (Device->IF == IF_SPI) Device->Framebuffer = heap_caps_calloc( 1, Device->FramebufferSize, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA ); + else +#endif + Device->Framebuffer = calloc( 1, Device->FramebufferSize ); #endif // need to be off and disable display RAM diff --git a/components/display/SSD1306.c b/components/display/SSD1306.c index f0a1b095..044aca24 100644 --- a/components/display/SSD1306.c +++ b/components/display/SSD1306.c @@ -78,19 +78,25 @@ static void SetContrast( struct GDS_Device* Device, uint8_t Contrast ) { static bool Init( struct GDS_Device* Device ) { Device->FramebufferSize = ( Device->Width * Device->Height ) / 8; + +// benchmarks showed little gain to have SPI memory already in IRAL vs letting driver copy +#ifdef SHADOW_BUFFER Device->Framebuffer = calloc( 1, Device->FramebufferSize ); NullCheck( Device->Framebuffer, return false ); - -#ifdef SHADOW_BUFFER #ifdef USE_IRAM - // benchmarks showed little gain to have SPI memory already in IRAL vs letting driver copy if (Device->IF == IF_SPI) Device->Shadowbuffer = heap_caps_malloc( Device->FramebufferSize, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA ); else -#else - Device->Shadowbuffer = malloc( Device->FramebufferSize ); #endif + Device->Shadowbuffer = malloc( Device->FramebufferSize ); NullCheck( Device->Shadowbuffer, return false ); memset(Device->Shadowbuffer, 0xFF, Device->FramebufferSize); +#else // not SHADOW_BUFFER +#ifdef USE_IRAM + // benchmarks showed little gain to have SPI memory already in IRAL vs letting driver copy + if (Device->IF == IF_SPI) Device->Framebuffer = heap_caps_calloc( 1, Device->FramebufferSize, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA ); + else +#endif + Device->Framebuffer = calloc( 1, Device->FramebufferSize ); #endif // need to be off and disable display RAM diff --git a/components/display/SSD132x.c b/components/display/SSD132x.c index d93c0018..0508554c 100644 --- a/components/display/SSD132x.c +++ b/components/display/SSD132x.c @@ -32,7 +32,27 @@ struct SSD132x_Private { uint8_t Model; }; -// Functions are not deckared to minimize # of lines +static const unsigned char BitReverseTable256[] = +{ + 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, + 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, + 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, + 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, + 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, + 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, + 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, + 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, + 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1, + 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, + 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, + 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD, + 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, + 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, + 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, + 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF +}; + +// Functions are not declared to minimize # of lines static void SetColumnAddress( struct GDS_Device* Device, uint8_t Start, uint8_t End ) { Device->WriteCommand( Device, 0x15 ); @@ -48,17 +68,15 @@ static void SetRowAddress( struct GDS_Device* Device, uint8_t Start, uint8_t End static void Update4( struct GDS_Device* Device ) { struct SSD132x_Private *Private = (struct SSD132x_Private*) Device->Private; - int r; - + // always update by full lines SetColumnAddress( Device, 0, Device->Width / 2 - 1); #ifdef SHADOW_BUFFER uint16_t *optr = (uint16_t*) Device->Shadowbuffer, *iptr = (uint16_t*) Device->Framebuffer; bool dirty = false; - int page; - for (r = 0, page = 0; r < Device->Height; r++) { + for (int r = 0, page = 0; r < Device->Height; r++) { // look for change and update shadow (cheap optimization = width always / by 2) for (int c = Device->Width / 2 / 2; --c >= 0;) { if (*optr != *iptr) { @@ -74,10 +92,10 @@ static void Update4( struct GDS_Device* Device ) { SetRowAddress( Device, r - page + 1, r ); // own use of IRAM has not proven to be much better than letting SPI do its copy if (Private->iRAM) { - memcpy(Private->iRAM, Device->Shadowbuffer + (r - page + 1) * Device->Width / 2, Device->Width * page / 2 ); + memcpy(Private->iRAM, Device->Shadowbuffer + (r - page + 1) * Device->Width / 2, page * Device->Width / 2 ); Device->WriteData( Device, Private->iRAM, Device->Width * page / 2 ); } else { - Device->WriteData( Device, Device->Shadowbuffer + (r - page + 1) * Device->Width / 2, Device->Width * page / 2 ); + Device->WriteData( Device, Device->Shadowbuffer + (r - page + 1) * Device->Width / 2, page * Device->Width / 2 ); } dirty = false; } @@ -85,17 +103,27 @@ static void Update4( struct GDS_Device* Device ) { } } #else - for (r = 0; r < Device->Height; r += Private->PageSize) { + for (int r = 0; r < Device->Height; r += Private->PageSize) { SetRowAddress( Device, r, r + Private->PageSize - 1 ); - Device->WriteData( Device, Device->Framebuffer + r * Device->Width / 2, Device->Width * Private->PageSize / 2 ); + if (Private->iRAM) { + memcpy(Private->iRAM, Device->Framebuffer + r * Device->Width / 2, Private->PageSize * Device->Width / 2 ); + Device->WriteData( Device, Private->iRAM, Private->PageSize * Device->Width / 2 ); + } else { + Device->WriteData( Device, Device->Framebuffer + r * Device->Width / 2, Private->PageSize * Device->Width / 2 ); + } } #endif } +/* + We have to make a choice here: either we go by row one by one and send lots of + small packets on the serial interface or we do a page of N rows once at least + a change has been detected. So far, choice is to go one-by-one +*/ static void Update1( struct GDS_Device* Device ) { #ifdef SHADOW_BUFFER // not sure the compiler does not have to redo all calculation in for loops, so local it is - int width = Device->Width, rows = Device->Height / 8; + int width = Device->Width / 8, rows = Device->Height; uint8_t *optr = Device->Shadowbuffer, *iptr = Device->Framebuffer; // by row, find first and last columns that have been updated @@ -117,13 +145,38 @@ static void Update1( struct GDS_Device* Device ) { } } #else - // automatic counter and end Page/Column - SetColumnAddress( Device, 0, Device->Width - 1); - SetPageAddress( Device, 0, Device->Height / 8 - 1); + // automatic counter and end Row/Column + SetColumnAddress( Device, 0, Device->Width / 8 - 1); + SetRowAddress( Device, 0, Device->Height - 1); Device->WriteData( Device, Device->Framebuffer, Device->FramebufferSize ); #endif } +// in 1 bit mode, SSD1326 has a different memory map than SSD1306 and SH1106 +static void IRAM_ATTR DrawPixel1Fast( struct GDS_Device* Device, int X, int Y, int Color ) { + uint32_t XBit = ( X & 0x07 ); + uint8_t* FBOffset = Device->Framebuffer + ( ( Y * Device->Width + X ) >> 3 ); + + if ( Color == GDS_COLOR_XOR ) { + *FBOffset ^= BIT( 7 - XBit ); + } else { + // we might be able to save the 7-Xbit using BitRemap (A0 bit 2) + *FBOffset = ( Color == GDS_COLOR_WHITE ) ? *FBOffset | BIT( 7 - XBit ) : *FBOffset & ~BIT( 7 - XBit ); + } +} + +static void DrawBitmapCBR(struct GDS_Device* Device, uint8_t *Data, int Width, int Height, int Color ) { + uint8_t *optr = Device->Framebuffer; + + if (!Height) Height = Device->Height; + if (!Width) Width = Device->Width; + + // just do bitreverse and if BitRemap works, there will be even nothing to do + for (int i = Height * Width >> 3; --i >= 0;) *optr++ = BitReverseTable256[*Data++]; + + // Dirty is set for us +} + static void SetHFlip( struct GDS_Device* Device, bool On ) { struct SSD132x_Private *Private = (struct SSD132x_Private*) Device->Private; if (Private->Model == SSD1326) Private->ReMap = On ? (Private->ReMap | ((1 << 0) | (1 << 2))) : (Private->ReMap & ~((1 << 0) | (1 << 2))); @@ -163,14 +216,38 @@ static bool Init( struct GDS_Device* Device ) { Device->Framebuffer = calloc( 1, Device->FramebufferSize ); NullCheck( Device->Framebuffer, return false ); +// benchmarks showed little gain to have SPI memory already in IRAM vs letting driver copy #ifdef SHADOW_BUFFER - Device->Shadowbuffer = malloc( Device->FramebufferSize ); - NullCheck( Device->Shadowbuffer, return false ); + Device->Framebuffer = calloc( 1, Device->FramebufferSize ); + NullCheck( Device->Framebuffer, return false ); +#ifdef USE_IRAM + if (Device->IF == IF_SPI) { + if (Device->Depth == 1) { + Device->Shadowbuffer = heap_caps_malloc( Device->FramebufferSize, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA ); + } else { + Device->Shadowbuffer = malloc( Device->FramebufferSize ); + Private->iRAM = heap_caps_malloc( Private->PageSize * Device->Width / 2, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA ); + } + } else +#endif + Device->Shadowbuffer = malloc( Device->FramebufferSize ); memset(Device->Shadowbuffer, 0xFF, Device->FramebufferSize); +#else // not SHADOW_BUFFER +#ifdef USE_IRAM + if (Device->IF == IF_SPI) { + if (Device->Depth == 1) { + Device->Framebuffer = heap_caps_calloc( 1, Device->FramebufferSize, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA ); + } else { + Device->Framebuffer = calloc( 1, Device->FramebufferSize ); + Private->iRAM = heap_caps_malloc( Private->PageSize * Device->Width / 2, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA ); + } + } else +#endif + Device->Framebuffer = calloc( 1, Device->FramebufferSize ); #endif ESP_LOGI(TAG, "SSD1326/7 with bit depth %u, page %u, iRAM %p", Device->Depth, Private->PageSize, Private->iRAM); - + // need to be off and disable display RAM Device->DisplayOff( Device ); Device->WriteCommand( Device, 0xA5 ); @@ -225,11 +302,19 @@ struct GDS_Device* SSD132x_Detect(char *Driver, struct GDS_Device* Device) { else return NULL; if (!Device) Device = calloc(1, sizeof(struct GDS_Device)); + *Device = SSD132x; ((struct SSD132x_Private*) Device->Private)->Model = Model; + sscanf(Driver, "%*[^:]:%c", &Device->Depth); - if (Model == SSD1326 && Device->Depth == 1) Device->Update = Update1; - else Device->Depth = 4; + + if (Model == SSD1326 && Device->Depth == 1) { + Device->Update = Update1; + Device->DrawPixelFast = DrawPixel1Fast; + Device->DrawBitmapCBR = DrawBitmapCBR; + } else { + Device->Depth = 4; + } return Device; } \ No newline at end of file diff --git a/components/display/core/gds.c b/components/display/core/gds.c index 6cec45d2..9b7a1c9a 100644 --- a/components/display/core/gds.c +++ b/components/display/core/gds.c @@ -21,7 +21,7 @@ static struct GDS_Device Display; static char TAG[] = "gds"; -struct GDS_Device* GDS_AutoDetect( char *Driver, GDS_DetectFunc* DetectFunc[] ) { +struct GDS_Device* GDS_AutoDetect( char *Driver, GDS_DetectFunc* DetectFunc[] ) { for (int i = 0; DetectFunc[i]; i++) { if (DetectFunc[i](Driver, &Display)) { ESP_LOGD(TAG, "Detected driver %p", &Display); @@ -53,38 +53,61 @@ void GDS_ClearExt(struct GDS_Device* Device, bool full, ...) { } void GDS_Clear( struct GDS_Device* Device, int Color ) { + if (Device->Depth == 1) Color = Color == GDS_COLOR_BLACK ? 0 : 0xff; + else if (Device->Depth == 4) Color = Color | (Color << 4); memset( Device->Framebuffer, Color, Device->FramebufferSize ); Device->Dirty = true; } void GDS_ClearWindow( struct GDS_Device* Device, int x1, int y1, int x2, int y2, int Color ) { - // driver can provide onw optimized clear window + // driver can provide own optimized clear window if (Device->ClearWindow) { Device->ClearWindow( Device, x1, y1, x2, y2, Color ); } else if (Device->Depth == 1) { // single shot if we erase all screen if (x2 - x1 == Device->Width - 1 && y2 - y1 == Device->Height - 1) { - memset( Device->Framebuffer, Color, Device->FramebufferSize ); + memset( Device->Framebuffer, Color == GDS_COLOR_BLACK ? 0 : 0xff, Device->FramebufferSize ); } else { uint8_t _Color = Color == GDS_COLOR_BLACK ? 0: 0xff; uint8_t Width = Device->Width; // try to do byte processing as much as possible - for (int c = x1; c <= x2; c++) { + int c; + for (c = x1; c <= x2; c++) { int r = y1; while (r & 0x07 && r <= y2) GDS_DrawPixelFast( Device, c, r++, Color); - for (; (r >> 3) < (y2 >> 3); r++) Device->Framebuffer[(r >> 3) * Width + c] = _Color; - // memset(Device->Framebuffer + (r >> 3) * Width, _Color, (y2 >> 3) - (r >> 3)); + //for (; (r >> 3) < (y2 >> 3); r++) Device->Framebuffer[(r >> 3) * Width + c] = _Color; + memset(Device->Framebuffer + (r >> 3) * Width + c, _Color, (y2 - r) >> 3); while (r <= y2) GDS_DrawPixelFast( Device, c, r++, Color); } - } + } + } if (Device->Depth == 4) { + if (x2 - x1 == Device->Width - 1 && y2 - y1 == Device->Height - 1) { + // we assume color is 0..15 + memset( Device->Framebuffer, Color | (Color << 4), Device->FramebufferSize ); + } else { + uint8_t _Color = Color | (Color << 4); + uint8_t Width = Device->Width; + // try to do byte processing as much as possible + int r; + for (r = y1; r <= y2; r++) { + int c = x1; + if (c & 0x01) GDS_DrawPixelFast( Device, c++, r, Color); + //for (; (c >> 1) < (x2 >> 1); c++) Device->Framebuffer[(r * Width + c) >> 1] = _Color; + memset(Device->Framebuffer + ((r * Width +c) >> 1), _Color, (x2 - c) >> 1); + if (c < x2) GDS_DrawPixelFast( Device, c, r, Color); + } + } } else { - for (int y = y1; y <= y2; y++) { - for (int x = x1; x <= x2; x++) { + int y; + for (y = y1; y <= y2; y++) { + int x; + for (x = x1; x <= x2; x++) { GDS_DrawPixelFast( Device, x, y, Color); - } - } - } - + } + } + } + + // make sure diplay will do update Device->Dirty = true; } diff --git a/components/display/core/gds_draw.c b/components/display/core/gds_draw.c index 6b2f5c3e..f22d1d00 100644 --- a/components/display/core/gds_draw.c +++ b/components/display/core/gds_draw.c @@ -197,7 +197,9 @@ void GDS_DrawBitmapCBR(struct GDS_Device* Device, uint8_t *Data, int Width, int if (!Width) Width = Device->Width; Height >>= 3; - if (Device->Depth == 1) { + if (Device->DrawBitmapCBR) { + Device->DrawBitmapCBR( Device, Data, Width, Height, Color ); + } else if (Device->Depth == 1) { // need to do row/col swap and bit-reverse for (int r = 0; r < Height; r++) { uint8_t *optr = Device->Framebuffer + r*Device->Width, *iptr = Data + r; @@ -276,84 +278,36 @@ void GDS_DrawBitmapCBR(struct GDS_Device* Device, uint8_t *Data, int Width, int void GDS_DrawRGB16( struct GDS_Device* Device, int x, int y, int Width, int Height, int RGB_Mode, uint16_t **Image ) { if (Device->DrawRGB16) { Device->DrawRGB16( Device, x, y, Width, Height, RGB_Mode, Image ); - } else if (Device->Depth == 4) { - for (int c = 0; c < Width; c++) { - for (int r = 0; r < Height; r++) { - int pixel = Image[r][c]; - switch(RGB_Mode) { - case GDS_RGB565: - pixel = (((pixel & 0x1f) * 11 + (((pixel >> 5) & 0x3f) * 59) / 2 + (pixel >> 11) * 30) / 100) >> 1; - break; - case GDS_RGB555: - pixel = (((pixel & 0x1f) * 11 + ((pixel >> 5) & 0x1f) * 59 + (pixel >> 10) * 30) / 100) >> 1; - break; - case GDS_RGB444: - pixel = ((pixel & 0x0f) * 11 + ((pixel >> 4) & 0x0f) * 59 + (pixel >> 8) * 30) / 100; - break; - case GDS_RGB8_GRAY: - pixel = Image[r][c] >> 4; - break; - } - GDS_DrawPixel( Device, c + x, r + y, pixel ); + } else { + int Scale = Device->Depth < 5 ? 5 - Device->Depth : 0; + switch(RGB_Mode) { + case GDS_RGB565: + for (int c = 0; c < Width; c++) { + for (int r = 0; r < Height; r++) { + int pixel = Image[r][c]; + pixel = ((pixel & 0x1f) * 11 + ((((pixel >> 5) & 0x3f) * 59) >> 1) + (pixel >> 11) * 30) / 100; + GDS_DrawPixel( Device, c + x, r + y, pixel >> Scale); + } } - } - } else if (Device->Depth == 1) { - for (int c = 0; c < Width; c++) { - for (int r = 0; r < Height; r++) { - int pixel = Image[r][c]; - switch(RGB_Mode) { - case GDS_RGB565: - pixel = (((pixel & 0x1f) * 21 + (((pixel >> 5) & 0x3f) * 71) / 2+ (pixel >> 11) * 7) / 100) >> 4; - break; - case GDS_RGB555: - pixel = (((pixel & 0x1f) * 21 + ((pixel >> 5) & 0x1f) * 71 + (pixel >> 10) * 7) / 100) >> 4; - break; - case GDS_RGB444: - pixel = (((pixel & 0x0f) * 21 + ((pixel >> 4) & 0x0f) * 71 + (pixel >> 8) * 7) / 100) >> 3; - break; - case GDS_RGB8_GRAY: - pixel = Image[r][c] >> 7; - } - GDS_DrawPixel( Device, c + x, r + y, pixel); + break; + case GDS_RGB555: + for (int c = 0; c < Width; c++) { + for (int r = 0; r < Height; r++) { + int pixel = Image[r][c]; + pixel = ((pixel & 0x1f) * 11 + ((pixel >> 5) & 0x1f) * 59 + (pixel >> 10) * 30) / 100; + GDS_DrawPixel( Device, c + x, r + y, pixel >> Scale); + } } + break; + case GDS_RGB444: + for (int c = 0; c < Width; c++) { + for (int r = 0; r < Height; r++) { + int pixel = Image[r][c]; + pixel = (pixel & 0x0f) * 11 + ((pixel >> 4) & 0x0f) * 59 + (pixel >> 8) * 30; + GDS_DrawPixel( Device, c + x, r + y, pixel >> (Scale - 1)); + } + } + break; } } } - -/**************************************************************************************** - * Process graphic display data MSBit first - * WARNING: this has not been tested yet - */ - /* -static void DrawBitmap(int x1, int y1, int x2, int y2, bool by_column, bool MSb, u8_t *data) { - // default end point to display size - if (x2 == -1) x2 = Display.Width - 1; - if (y2 == -1) y2 = Display.Height - 1; - - display->dirty = true; - - // not a boundary draw - // same comment about bit depth - if (y1 % 8 || y2 % 8 || x1 % 8 | x2 % 8) { - ESP_LOGW(TAG, "can't write on non cols/rows boundaries for now"); - } else { - // set addressing mode to match data - if (by_column) { - // copy the window and do row/col exchange - for (int r = y1/8; r <= y2/8; r++) { - uint8_t *optr = Display.Framebuffer + r*Display.Width + x1, *iptr = data + r; - for (int c = x1; c <= x2; c++) { - *optr++ = MSb ? BitReverseTable256[*iptr] : *iptr; - iptr += (y2-y1)/8 + 1; - } - } - } else { - // just copy the window inside the frame buffer - for (int r = y1/8; r <= y2/8; r++) { - uint8_t *optr = Display.Framebuffer + r*Display.Width + x1, *iptr = data + r*(x2-x1+1); - for (int c = x1; c <= x2; c++) *optr++ = *iptr++; - } - } - } -} -*/ diff --git a/components/display/core/gds_draw.h b/components/display/core/gds_draw.h index 048fa354..9daf654a 100644 --- a/components/display/core/gds_draw.h +++ b/components/display/core/gds_draw.h @@ -11,7 +11,7 @@ extern "C" { struct GDS_Device; -enum { GDS_RGB565, GDS_RGB555, GDS_RGB444, GDS_RGB8_GRAY }; +enum { GDS_RGB565, GDS_RGB555, GDS_RGB444 }; #ifndef _GDS_PRIVATE_H_ void IRAM_ATTR GDS_DrawPixelFast( struct GDS_Device* Device, int X, int Y, int Color ); diff --git a/components/display/core/gds_private.h b/components/display/core/gds_private.h index 3e2676ff..bc883009 100644 --- a/components/display/core/gds_private.h +++ b/components/display/core/gds_private.h @@ -40,7 +40,7 @@ #define MAX_LINES 8 #if ! defined BIT -#define BIT( n ) ( 1 << n ) +#define BIT( n ) ( 1 << ( n ) ) #endif struct GDS_Device; @@ -103,6 +103,7 @@ struct GDS_Device { void (*Update)( struct GDS_Device* Device ); // must provide for depth other than 1 (vertical) and 4 (may provide for optimization) void (*DrawPixelFast)( struct GDS_Device* Device, int X, int Y, int Color ); + void (*DrawBitmapCBR)(struct GDS_Device* Device, uint8_t *Data, int Width, int Height, int Color ); // may provide for optimization void (*DrawRGB16)( struct GDS_Device* Device, int x, int y, int Width, int Height, int RGB_Mode, uint16_t **Image ); void (*ClearWindow)( struct GDS_Device* Device, int x1, int y1, int x2, int y2, int Color ); diff --git a/components/display/display.c b/components/display/display.c index f626cbd9..e5e28a70 100644 --- a/components/display/display.c +++ b/components/display/display.c @@ -83,7 +83,7 @@ void display_init(char *welcome) { if ((p = strcasestr(config, "width")) != NULL) width = atoi(strchr(p, '=') + 1); if ((p = strcasestr(config, "height")) != NULL) height = atoi(strchr(p, '=') + 1); - + // so far so good if (display && width > 0 && height > 0) { // Detect driver interface diff --git a/components/squeezelite/display.c b/components/squeezelite/display.c index d33b8b09..c79a6bfb 100644 --- a/components/squeezelite/display.c +++ b/components/squeezelite/display.c @@ -637,7 +637,7 @@ static void visu_update(void) { // reset bars for all cases first for (int i = visu.n; --i >= 0;) visu.bars[i].current = 0; - if (visu_export.running && visu_export.running) { + if (visu_export.running) { if (visu.mode == VISU_VUMETER) { s16_t *iptr = visu_export.buffer; @@ -705,15 +705,20 @@ static void visu_update(void) { visu_export.level = 0; pthread_mutex_unlock(&visu_export.mutex); - GDS_ClearExt(display, false, false, visu.col, visu.row, visu.col + visu.width - 1, visu.row + visu.height - 1); - + // don't refresh screen if all max are 0 (we were are somewhat idle) + int clear = 0; + for (int i = visu.n; --i >= 0;) clear = max(clear, visu.bars[i].max); + if (clear) GDS_ClearExt(display, false, false, visu.col, visu.row, visu.col + visu.width - 1, visu.row + visu.height - 1); + + // there is much more optimization to be done here, like not redrawing bars unless needed for (int i = visu.n; --i >= 0;) { int x1 = visu.col + visu.border + visu.bar_border + i*(visu.bar_width + visu.bar_gap); int y1 = visu.row + visu.height - 1; if (visu.bars[i].current > visu.bars[i].max) visu.bars[i].max = visu.bars[i].current; else if (visu.bars[i].max) visu.bars[i].max--; - + else if (!clear) continue; + for (int j = 0; j <= visu.bars[i].current; j += 2) GDS_DrawLine(display, x1, y1 - j, x1 + visu.bar_width - 1, y1 - j, GDS_COLOR_WHITE);