From e85a3cddf109a7398fed8f1c44f63aee5896787b Mon Sep 17 00:00:00 2001 From: philippe44 Date: Thu, 16 Nov 2023 22:52:18 -0800 Subject: [PATCH] GDS optimization --- components/display/SH1122.c | 6 --- components/display/core/gds.c | 76 +++++++++++++++++++++++++-- components/display/core/gds_draw.c | 24 ++++----- components/display/core/gds_private.h | 62 +--------------------- components/display/core/gds_text.c | 2 +- 5 files changed, 85 insertions(+), 85 deletions(-) diff --git a/components/display/SH1122.c b/components/display/SH1122.c index 867daf9c..72e9d5be 100644 --- a/components/display/SH1122.c +++ b/components/display/SH1122.c @@ -88,11 +88,6 @@ static void Update( struct GDS_Device* Device ) { #endif } -static void DrawPixelFast4( struct GDS_Device* Device, int X, int Y, int Color ) { - uint8_t* FBOffset = Device->Framebuffer + ( (Y * Device->Width >> 1) + (X >> 1)); - *FBOffset = X & 0x01 ? ((*FBOffset & 0xf0) | (Color & 0x0f)) : (*FBOffset & 0x0f) | ((Color & 0x0f) << 4); -} - static void SetLayout( struct GDS_Device* Device, struct GDS_Layout *Layout ) { if (Layout->HFlip) { Device->WriteCommand( Device, 0x40 + 0x20 ); @@ -165,7 +160,6 @@ static bool Init( struct GDS_Device* Device ) { static const struct GDS_Device SH1122 = { .DisplayOn = DisplayOn, .DisplayOff = DisplayOff, .SetContrast = SetContrast, - .DrawPixelFast = DrawPixelFast4, .SetLayout = SetLayout, .Update = Update, .Init = Init, .Mode = GDS_GRAYSCALE, .Depth = 4, diff --git a/components/display/core/gds.c b/components/display/core/gds.c index e2479f49..2fd4dae3 100644 --- a/components/display/core/gds.c +++ b/components/display/core/gds.c @@ -109,7 +109,7 @@ void GDS_ClearWindow( struct GDS_Device* Device, int x1, int y1, int x2, int y2, int c = x1; // for a row that is not on a boundary, no optimization possible while (r & 0x07 && r <= y2) { - for (c = x1; c <= x2; c++) DrawPixelFast( Device, c, r, Color ); + for (c = x1; c <= x2; c++) Device->DrawPixelFast( Device, c, r, Color ); r++; } // go fast if we have more than 8 lines to write @@ -117,7 +117,7 @@ void GDS_ClearWindow( struct GDS_Device* Device, int x1, int y1, int x2, int y2, memset(optr + Width * r + x1, _Color, x2 - x1 + 1); r += 8; } else while (r <= y2) { - for (c = x1; c <= x2; c++) DrawPixelFast( Device, c, r, Color ); + for (c = x1; c <= x2; c++) Device->DrawPixelFast( Device, c, r, Color ); r++; } } @@ -133,10 +133,10 @@ void GDS_ClearWindow( struct GDS_Device* Device, int x1, int y1, int x2, int y2, // try to do byte processing as much as possible for (int r = y1; r <= y2; r++) { int c = x1; - if (c & 0x01) DrawPixelFast( Device, c++, r, Color); + if (c & 0x01) Device->DrawPixelFast( Device, c++, r, Color); int chunk = (x2 - c + 1) >> 1; memset(optr + ((r * Width + c) >> 1), _Color, chunk); - if (c + chunk <= x2) DrawPixelFast( Device, x2, r, Color); + if (c + chunk <= x2) Device->DrawPixelFast( Device, x2, r, Color); } } } else if (Device->Depth == 8) { @@ -148,7 +148,7 @@ void GDS_ClearWindow( struct GDS_Device* Device, int x1, int y1, int x2, int y2, } else { for (int y = y1; y <= y2; y++) { for (int x = x1; x <= x2; x++) { - DrawPixelFast( Device, x, y, Color); + Device->DrawPixelFast( Device, x, y, Color); } } } @@ -171,10 +171,76 @@ bool GDS_Reset( struct GDS_Device* Device ) { return true; } +static void IRAM_ATTR DrawPixel1Fast( struct GDS_Device* Device, int X, int Y, int Color ) { + uint32_t YBit = ( Y & 0x07 ); + uint8_t* FBOffset; + + /* + * We only need to modify the Y coordinate since the pitch + * of the screen is the same as the width. + * Dividing Y by 8 gives us which row the pixel is in but not + * the bit position. + */ + Y>>= 3; + + FBOffset = Device->Framebuffer + ( ( Y * Device->Width ) + X ); + + if ( Color == GDS_COLOR_XOR ) { + *FBOffset ^= BIT( YBit ); + } else { + *FBOffset = ( Color == GDS_COLOR_BLACK ) ? *FBOffset & ~BIT( YBit ) : *FBOffset | BIT( YBit ); + } +} + +static void IRAM_ATTR DrawPixel4Fast( struct GDS_Device* Device, int X, int Y, int Color ) { + uint8_t* FBOffset = Device->Framebuffer + ( (Y * Device->Width >> 1) + (X >> 1)); + *FBOffset = X & 0x01 ? (*FBOffset & 0x0f) | ((Color & 0x0f) << 4) : ((*FBOffset & 0xf0) | (Color & 0x0f)); +} + +static void IRAM_ATTR DrawPixel4FastHigh( struct GDS_Device* Device, int X, int Y, int Color ) { + uint8_t* FBOffset = Device->Framebuffer + ( (Y * Device->Width >> 1) + (X >> 1)); + *FBOffset = X & 0x01 ? ((*FBOffset & 0xf0) | (Color & 0x0f)) : (*FBOffset & 0x0f) | ((Color & 0x0f) << 4); +} + +static void IRAM_ATTR DrawPixel8Fast( struct GDS_Device* Device, int X, int Y, int Color ) { + Device->Framebuffer[Y * Device->Width + X] = Color; +} + +// assumes that Color is 16 bits R..RG..GB..B from MSB to LSB and FB wants 1st serialized byte to start with R +static void IRAM_ATTR DrawPixel16Fast( struct GDS_Device* Device, int X, int Y, int Color ) { + uint16_t* FBOffset = (uint16_t*) Device->Framebuffer + Y * Device->Width + X; + *FBOffset = __builtin_bswap16(Color); +} + +// assumes that Color is 18 bits RGB from MSB to LSB RRRRRRGGGGGGBBBBBB, so byte[0] is B +// FB is 3-bytes packets and starts with R for serialization so 0,1,2 ... = xxRRRRRR xxGGGGGG xxBBBBBB +static void IRAM_ATTR DrawPixel18Fast( struct GDS_Device* Device, int X, int Y, int Color ) { + uint8_t* FBOffset = Device->Framebuffer + (Y * Device->Width + X) * 3; + *FBOffset++ = Color >> 12; *FBOffset++ = (Color >> 6) & 0x3f; *FBOffset = Color & 0x3f; +} + +// assumes that Color is 24 bits RGB from MSB to LSB RRRRRRRRGGGGGGGGBBBBBBBB, so byte[0] is B +// FB is 3-bytes packets and starts with R for serialization so 0,1,2 ... = RRRRRRRR GGGGGGGG BBBBBBBB +static void IRAM_ATTR DrawPixel24Fast( struct GDS_Device* Device, int X, int Y, int Color ) { + uint8_t* FBOffset = Device->Framebuffer + (Y * Device->Width + X) * 3; + *FBOffset++ = Color >> 16; *FBOffset++ = Color >> 8; *FBOffset = Color; +} + bool GDS_Init( struct GDS_Device* Device ) { if (Device->Depth > 8) Device->FramebufferSize = Device->Width * Device->Height * ((8 + Device->Depth - 1) / 8); else Device->FramebufferSize = (Device->Width * Device->Height) / (8 / Device->Depth); + + // set the proper DrawPixel function if not already set by driver + if (!Device->DrawPixelFast) { + if (Device->Depth == 1) Device->DrawPixelFast = DrawPixel1Fast; + else if (Device->Depth == 4 && Device->HighNibble) Device->DrawPixelFast = DrawPixel4FastHigh; + else if (Device->Depth == 4) Device->DrawPixelFast = DrawPixel4Fast; + else if (Device->Depth == 8) Device->DrawPixelFast = DrawPixel8Fast; + else if (Device->Depth == 16) Device->DrawPixelFast = DrawPixel16Fast; + else if (Device->Depth == 24 && Device->Mode == GDS_RGB666) Device->DrawPixelFast = DrawPixel18Fast; + else if (Device->Depth == 24 && Device->Mode == GDS_RGB888) Device->DrawPixelFast = DrawPixel24Fast; + } // allocate FB unless explicitely asked not to if (!(Device->Alloc & GDS_ALLOC_NONE)) { diff --git a/components/display/core/gds_draw.c b/components/display/core/gds_draw.c index 727e1f99..e58d9afb 100644 --- a/components/display/core/gds_draw.c +++ b/components/display/core/gds_draw.c @@ -45,7 +45,7 @@ __attribute__( ( always_inline ) ) static inline void SwapInt( int* a, int* b ) } void IRAM_ATTR GDS_DrawPixelFast( struct GDS_Device* Device, int X, int Y, int Color ) { - DrawPixelFast( Device, X, Y, Color ); + Device->DrawPixelFast( Device, X, Y, Color ); } void IRAM_ATTR GDS_DrawPixel( struct GDS_Device* Device, int X, int Y, int Color ) { @@ -63,7 +63,7 @@ void GDS_DrawHLine( struct GDS_Device* Device, int x, int y, int Width, int Colo if (y < 0) y = 0; else if (y >= Device->Height) y = Device->Height - 1; - for ( ; x < XEnd; x++ ) DrawPixelFast( Device, x, y, Color ); + for ( ; x < XEnd; x++ ) Device->DrawPixelFast( Device, x, y, Color ); } void GDS_DrawVLine( struct GDS_Device* Device, int x, int y, int Height, int Color ) { @@ -97,7 +97,7 @@ static inline void DrawWideLine( struct GDS_Device* Device, int x0, int y0, int for ( ; x < x1; x++ ) { if ( IsPixelVisible( Device, x, y ) == true ) { - DrawPixelFast( Device, x, y, Color ); + Device->DrawPixelFast( Device, x, y, Color ); } if ( Error > 0 ) { @@ -126,7 +126,7 @@ static inline void DrawTallLine( struct GDS_Device* Device, int x0, int y0, int for ( ; y < y1; y++ ) { if ( IsPixelVisible( Device, x, y ) == true ) { - DrawPixelFast( Device, x, y, Color ); + Device->DrawPixelFast( Device, x, y, Color ); } if ( Error > 0 ) { @@ -348,14 +348,14 @@ void GDS_DrawBitmapCBR(struct GDS_Device* Device, uint8_t *Data, int Width, int // don't know bitdepth, use brute-force solution for (int i = Width * Height, r = 0, c = 0; --i >= 0;) { uint8_t Byte = *Data++; - DrawPixelFast( Device, c, (r << 3) + 7, (Byte & 0x01) * Color ); Byte >>= 1; - DrawPixelFast( Device, c, (r << 3) + 6, (Byte & 0x01) * Color ); Byte >>= 1; - DrawPixelFast( Device, c, (r << 3) + 5, (Byte & 0x01) * Color ); Byte >>= 1; - DrawPixelFast( Device, c, (r << 3) + 4, (Byte & 0x01) * Color ); Byte >>= 1; - DrawPixelFast( Device, c, (r << 3) + 3, (Byte & 0x01) * Color ); Byte >>= 1; - DrawPixelFast( Device, c, (r << 3) + 2, (Byte & 0x01) * Color ); Byte >>= 1; - DrawPixelFast( Device, c, (r << 3) + 1, (Byte & 0x01) * Color ); Byte >>= 1; - DrawPixelFast( Device, c, (r << 3) + 0, (Byte & 0x01) * Color ); + Device->DrawPixelFast( Device, c, (r << 3) + 7, (Byte & 0x01) * Color ); Byte >>= 1; + Device->DrawPixelFast( Device, c, (r << 3) + 6, (Byte & 0x01) * Color ); Byte >>= 1; + Device->DrawPixelFast( Device, c, (r << 3) + 5, (Byte & 0x01) * Color ); Byte >>= 1; + Device->DrawPixelFast( Device, c, (r << 3) + 4, (Byte & 0x01) * Color ); Byte >>= 1; + Device->DrawPixelFast( Device, c, (r << 3) + 3, (Byte & 0x01) * Color ); Byte >>= 1; + Device->DrawPixelFast( Device, c, (r << 3) + 2, (Byte & 0x01) * Color ); Byte >>= 1; + Device->DrawPixelFast( Device, c, (r << 3) + 1, (Byte & 0x01) * Color ); Byte >>= 1; + Device->DrawPixelFast( Device, c, (r << 3) + 0, (Byte & 0x01) * Color ); if (++r == Height) { c++; r = 0; } } /* for better understanding, here is the mundane version diff --git a/components/display/core/gds_private.h b/components/display/core/gds_private.h index 74741e04..395c45d7 100644 --- a/components/display/core/gds_private.h +++ b/components/display/core/gds_private.h @@ -156,69 +156,9 @@ static inline bool IsPixelVisible( struct GDS_Device* Device, int x, int y ) { return Result; } -static inline void DrawPixel1Fast( struct GDS_Device* Device, int X, int Y, int Color ) { - uint32_t YBit = ( Y & 0x07 ); - uint8_t* FBOffset; - - /* - * We only need to modify the Y coordinate since the pitch - * of the screen is the same as the width. - * Dividing Y by 8 gives us which row the pixel is in but not - * the bit position. - */ - Y>>= 3; - - FBOffset = Device->Framebuffer + ( ( Y * Device->Width ) + X ); - - if ( Color == GDS_COLOR_XOR ) { - *FBOffset ^= BIT( YBit ); - } else { - *FBOffset = ( Color == GDS_COLOR_BLACK ) ? *FBOffset & ~BIT( YBit ) : *FBOffset | BIT( YBit ); - } -} - -static inline void DrawPixel4Fast( struct GDS_Device* Device, int X, int Y, int Color ) { - uint8_t* FBOffset = Device->Framebuffer + ( (Y * Device->Width >> 1) + (X >> 1)); - *FBOffset = X & 0x01 ? (*FBOffset & 0x0f) | ((Color & 0x0f) << 4) : ((*FBOffset & 0xf0) | (Color & 0x0f)); -} - -static inline void DrawPixel8Fast( struct GDS_Device* Device, int X, int Y, int Color ) { - Device->Framebuffer[Y * Device->Width + X] = Color; -} - -// assumes that Color is 16 bits R..RG..GB..B from MSB to LSB and FB wants 1st serialized byte to start with R -static inline void DrawPixel16Fast( struct GDS_Device* Device, int X, int Y, int Color ) { - uint16_t* FBOffset = (uint16_t*) Device->Framebuffer + Y * Device->Width + X; - *FBOffset = __builtin_bswap16(Color); -} - -// assumes that Color is 18 bits RGB from MSB to LSB RRRRRRGGGGGGBBBBBB, so byte[0] is B -// FB is 3-bytes packets and starts with R for serialization so 0,1,2 ... = xxRRRRRR xxGGGGGG xxBBBBBB -static inline void DrawPixel18Fast( struct GDS_Device* Device, int X, int Y, int Color ) { - uint8_t* FBOffset = Device->Framebuffer + (Y * Device->Width + X) * 3; - *FBOffset++ = Color >> 12; *FBOffset++ = (Color >> 6) & 0x3f; *FBOffset = Color & 0x3f; -} - -// assumes that Color is 24 bits RGB from MSB to LSB RRRRRRRRGGGGGGGGBBBBBBBB, so byte[0] is B -// FB is 3-bytes packets and starts with R for serialization so 0,1,2 ... = RRRRRRRR GGGGGGGG BBBBBBBB -static inline void DrawPixel24Fast( struct GDS_Device* Device, int X, int Y, int Color ) { - uint8_t* FBOffset = Device->Framebuffer + (Y * Device->Width + X) * 3; - *FBOffset++ = Color >> 16; *FBOffset++ = Color >> 8; *FBOffset = Color; -} - -static inline void IRAM_ATTR DrawPixelFast( struct GDS_Device* Device, int X, int Y, int Color ) { - if (Device->DrawPixelFast) Device->DrawPixelFast( Device, X, Y, Color ); - else if (Device->Depth == 4) DrawPixel4Fast( Device, X, Y, Color ); - else if (Device->Depth == 1) DrawPixel1Fast( Device, X, Y, Color ); - else if (Device->Depth == 16) DrawPixel16Fast( Device, X, Y, Color ); - else if (Device->Depth == 24 && Device->Mode == GDS_RGB666) DrawPixel18Fast( Device, X, Y, Color ); - else if (Device->Depth == 24 && Device->Mode == GDS_RGB888) DrawPixel24Fast( Device, X, Y, Color ); - else if (Device->Depth == 8) DrawPixel8Fast( Device, X, Y, Color ); -} - static inline void IRAM_ATTR DrawPixel( struct GDS_Device* Device, int x, int y, int Color ) { if ( IsPixelVisible( Device, x, y ) == true ) { - DrawPixelFast( Device, x, y, Color ); + Device->DrawPixelFast( Device, x, y, Color ); } } diff --git a/components/display/core/gds_text.c b/components/display/core/gds_text.c index b2ef8903..db764446 100644 --- a/components/display/core/gds_text.c +++ b/components/display/core/gds_text.c @@ -108,7 +108,7 @@ bool GDS_TextLine(struct GDS_Device* Device, int N, int Pos, int Attr, char *Tex int Y_min = max(0, Device->Lines[N].Y), Y_max = max(0, Device->Lines[N].Y + Device->Lines[N].Font->Height); for (int c = (Attr & GDS_TEXT_CLEAR_EOL) ? X : 0; c < Device->TextWidth; c++) for (int y = Y_min; y < Y_max; y++) - DrawPixelFast( Device, c, y, GDS_COLOR_BLACK ); + Device->DrawPixelFast( Device, c, y, GDS_COLOR_BLACK ); } GDS_FontDrawString( Device, X, Device->Lines[N].Y, Text, GDS_COLOR_WHITE );