Skip to content

Commit f80daa5

Browse files
authored
GFXcanvas: Allow subclass to take charge of buffer allocations (#465)
* GFXcanvas: Allow subclass to take charge of buffer allocations In Adafruit_dvhstx, the low level driver takes charge of the framebuffer allocations. Consequently, any allocation by the GFXcanvas class would be an unused waste of memory. Introduce a new constructor parameter `bool allocate_buffer=true`. The default preserves the old behavior of allocating the buffer in the constructor and freeing it in the destructor, while passing in `false` skips buffer allocation & freeing. In this case, the subclass must allocate the buffer before the first drawing operation (such as in its constructor or begin method), and free it in its own destructor or end method. The subclass can also freely change the buffer pointer at runtime, for instance in a swap method if the underlying framebuffer is double-buffered. * experimentally run a different clang-format This runs version 19.1.7: uvx clang-format -i *.cpp *.h the changes look similar to what was shown during CI * undo one edit that ci doesn't like
1 parent 1124b15 commit f80daa5

File tree

4 files changed

+95
-63
lines changed

4 files changed

+95
-63
lines changed

Adafruit_GFX.cpp

Lines changed: 48 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1758,12 +1758,21 @@ const uint8_t PROGMEM GFXcanvas1::GFXclrBit[] = {0x7F, 0xBF, 0xDF, 0xEF,
17581758
@brief Instatiate a GFX 1-bit canvas context for graphics
17591759
@param w Display width, in pixels
17601760
@param h Display height, in pixels
1761-
*/
1762-
/**************************************************************************/
1763-
GFXcanvas1::GFXcanvas1(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) {
1764-
uint32_t bytes = ((w + 7) / 8) * h;
1765-
if ((buffer = (uint8_t *)malloc(bytes))) {
1766-
memset(buffer, 0, bytes);
1761+
@param allocate_buffer If true, a buffer is allocated with malloc. If
1762+
false, the subclass must initialize the buffer before any drawing operation,
1763+
and free it in the destructor. If false (the default), the buffer is
1764+
allocated and freed by the library.
1765+
*/
1766+
/**************************************************************************/
1767+
GFXcanvas1::GFXcanvas1(uint16_t w, uint16_t h, bool allocate_buffer)
1768+
: Adafruit_GFX(w, h), buffer_owned(allocate_buffer) {
1769+
if (allocate_buffer) {
1770+
uint32_t bytes = ((w + 7) / 8) * h;
1771+
if ((buffer = (uint8_t *)malloc(bytes))) {
1772+
memset(buffer, 0, bytes);
1773+
}
1774+
} else {
1775+
buffer = nullptr;
17671776
}
17681777
}
17691778

@@ -1773,7 +1782,7 @@ GFXcanvas1::GFXcanvas1(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) {
17731782
*/
17741783
/**************************************************************************/
17751784
GFXcanvas1::~GFXcanvas1(void) {
1776-
if (buffer)
1785+
if (buffer && buffer_owned)
17771786
free(buffer);
17781787
}
17791788

@@ -2111,13 +2120,21 @@ void GFXcanvas1::drawFastRawHLine(int16_t x, int16_t y, int16_t w,
21112120
@brief Instatiate a GFX 8-bit canvas context for graphics
21122121
@param w Display width, in pixels
21132122
@param h Display height, in pixels
2114-
*/
2115-
/**************************************************************************/
2116-
GFXcanvas8::GFXcanvas8(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) {
2117-
uint32_t bytes = w * h;
2118-
if ((buffer = (uint8_t *)malloc(bytes))) {
2119-
memset(buffer, 0, bytes);
2120-
}
2123+
@param allocate_buffer If true, a buffer is allocated with malloc. If
2124+
false, the subclass must initialize the buffer before any drawing operation,
2125+
and free it in the destructor. If false (the default), the buffer is
2126+
allocated and freed by the library.
2127+
*/
2128+
/**************************************************************************/
2129+
GFXcanvas8::GFXcanvas8(uint16_t w, uint16_t h, bool allocate_buffer)
2130+
: Adafruit_GFX(w, h), buffer_owned(allocate_buffer) {
2131+
if (allocate_buffer) {
2132+
uint32_t bytes = w * h;
2133+
if ((buffer = (uint8_t *)malloc(bytes))) {
2134+
memset(buffer, 0, bytes);
2135+
}
2136+
} else
2137+
buffer = nullptr;
21212138
}
21222139

21232140
/**************************************************************************/
@@ -2126,7 +2143,7 @@ GFXcanvas8::GFXcanvas8(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) {
21262143
*/
21272144
/**************************************************************************/
21282145
GFXcanvas8::~GFXcanvas8(void) {
2129-
if (buffer)
2146+
if (buffer && buffer_owned)
21302147
free(buffer);
21312148
}
21322149

@@ -2379,12 +2396,21 @@ void GFXcanvas8::drawFastRawHLine(int16_t x, int16_t y, int16_t w,
23792396
@brief Instatiate a GFX 16-bit canvas context for graphics
23802397
@param w Display width, in pixels
23812398
@param h Display height, in pixels
2382-
*/
2383-
/**************************************************************************/
2384-
GFXcanvas16::GFXcanvas16(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) {
2385-
uint32_t bytes = w * h * 2;
2386-
if ((buffer = (uint16_t *)malloc(bytes))) {
2387-
memset(buffer, 0, bytes);
2399+
@param allocate_buffer If true, a buffer is allocated with malloc. If
2400+
false, the subclass must initialize the buffer before any drawing operation,
2401+
and free it in the destructor. If false (the default), the buffer is
2402+
allocated and freed by the library.
2403+
*/
2404+
/**************************************************************************/
2405+
GFXcanvas16::GFXcanvas16(uint16_t w, uint16_t h, bool allocate_buffer)
2406+
: Adafruit_GFX(w, h), buffer_owned(allocate_buffer) {
2407+
if (allocate_buffer) {
2408+
uint32_t bytes = w * h * 2;
2409+
if ((buffer = (uint16_t *)malloc(bytes))) {
2410+
memset(buffer, 0, bytes);
2411+
}
2412+
} else {
2413+
buffer = nullptr;
23882414
}
23892415
}
23902416

@@ -2394,7 +2420,7 @@ GFXcanvas16::GFXcanvas16(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) {
23942420
*/
23952421
/**************************************************************************/
23962422
GFXcanvas16::~GFXcanvas16(void) {
2397-
if (buffer)
2423+
if (buffer && buffer_owned)
23982424
free(buffer);
23992425
}
24002426

Adafruit_GFX.h

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ class Adafruit_GFX_Button {
309309
/// A GFX 1-bit canvas context for graphics
310310
class GFXcanvas1 : public Adafruit_GFX {
311311
public:
312-
GFXcanvas1(uint16_t w, uint16_t h);
312+
GFXcanvas1(uint16_t w, uint16_t h, bool allocate_buffer = true);
313313
~GFXcanvas1(void);
314314
void drawPixel(int16_t x, int16_t y, uint16_t color);
315315
void fillScreen(uint16_t color);
@@ -328,7 +328,9 @@ class GFXcanvas1 : public Adafruit_GFX {
328328
bool getRawPixel(int16_t x, int16_t y) const;
329329
void drawFastRawVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
330330
void drawFastRawHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
331-
uint8_t *buffer; ///< Raster data: no longer private, allow subclass access
331+
uint8_t *buffer; ///< Raster data: no longer private, allow subclass access
332+
bool buffer_owned; ///< If true, destructor will free buffer, else it will do
333+
///< nothing
332334

333335
private:
334336
#ifdef __AVR__
@@ -340,7 +342,7 @@ class GFXcanvas1 : public Adafruit_GFX {
340342
/// A GFX 8-bit canvas context for graphics
341343
class GFXcanvas8 : public Adafruit_GFX {
342344
public:
343-
GFXcanvas8(uint16_t w, uint16_t h);
345+
GFXcanvas8(uint16_t w, uint16_t h, bool allocate_buffer = true);
344346
~GFXcanvas8(void);
345347
void drawPixel(int16_t x, int16_t y, uint16_t color);
346348
void fillScreen(uint16_t color);
@@ -359,13 +361,15 @@ class GFXcanvas8 : public Adafruit_GFX {
359361
uint8_t getRawPixel(int16_t x, int16_t y) const;
360362
void drawFastRawVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
361363
void drawFastRawHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
362-
uint8_t *buffer; ///< Raster data: no longer private, allow subclass access
364+
uint8_t *buffer; ///< Raster data: no longer private, allow subclass access
365+
bool buffer_owned; ///< If true, destructor will free buffer, else it will do
366+
///< nothing
363367
};
364368

365369
/// A GFX 16-bit canvas context for graphics
366370
class GFXcanvas16 : public Adafruit_GFX {
367371
public:
368-
GFXcanvas16(uint16_t w, uint16_t h);
372+
GFXcanvas16(uint16_t w, uint16_t h, bool allocate_buffer = true);
369373
~GFXcanvas16(void);
370374
void drawPixel(int16_t x, int16_t y, uint16_t color);
371375
void fillScreen(uint16_t color);
@@ -385,7 +389,9 @@ class GFXcanvas16 : public Adafruit_GFX {
385389
uint16_t getRawPixel(int16_t x, int16_t y) const;
386390
void drawFastRawVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
387391
void drawFastRawHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
388-
uint16_t *buffer; ///< Raster data: no longer private, allow subclass access
392+
uint16_t *buffer; ///< Raster data: no longer private, allow subclass access
393+
bool buffer_owned; ///< If true, destructor will free buffer, else it will do
394+
///< nothing
389395
};
390396

391397
#endif // _ADAFRUIT_GFX_H

Adafruit_SPITFT.cpp

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -879,21 +879,21 @@ void Adafruit_SPITFT::initSPI(uint32_t freq, uint8_t spiMode) {
879879
DMA_ADDRESS_INCREMENT_STEP_SIZE_1;
880880
descriptor[d].DSTADDR.reg = (uint32_t)tft8.writePort;
881881
}
882-
#endif // __SAMD51
882+
#endif // __SAMD51
883883
} // end parallel-specific DMA setup
884884

885885
lastFillColor = 0x0000;
886886
lastFillLen = 0;
887887
dma.setCallback(dma_callback);
888888
return; // Success!
889889
// else clean up any partial allocation...
890-
} // end descriptor memalign()
890+
} // end descriptor memalign()
891891
free(pixelBuf[0]);
892892
pixelBuf[0] = pixelBuf[1] = NULL;
893-
} // end pixelBuf malloc()
894-
// Don't currently have a descriptor delete function in
895-
// ZeroDMA lib, but if we did, it would be called here.
896-
} // end addDescriptor()
893+
} // end pixelBuf malloc()
894+
// Don't currently have a descriptor delete function in
895+
// ZeroDMA lib, but if we did, it would be called here.
896+
} // end addDescriptor()
897897
dma.free(); // Deallocate DMA channel
898898
}
899899
#endif // end USE_SPI_DMA
@@ -1373,11 +1373,11 @@ void Adafruit_SPITFT::writeColor(uint16_t color, uint32_t len) {
13731373
dma.trigger();
13741374
while (dma_busy)
13751375
; // Wait for completion
1376-
// Unfortunately blocking is necessary. An earlier version returned
1377-
// immediately and checked dma_busy on startWrite() instead, but it
1378-
// turns out to be MUCH slower on many graphics operations (as when
1379-
// drawing lines, pixel-by-pixel), perhaps because it's a volatile
1380-
// type and doesn't cache. Working on this.
1376+
// Unfortunately blocking is necessary. An earlier version returned
1377+
// immediately and checked dma_busy on startWrite() instead, but it
1378+
// turns out to be MUCH slower on many graphics operations (as when
1379+
// drawing lines, pixel-by-pixel), perhaps because it's a volatile
1380+
// type and doesn't cache. Working on this.
13811381
#if defined(__SAMD51__) || defined(ARDUINO_SAMD_ZERO)
13821382
if (connection == TFT_HARD_SPI) {
13831383
// SAMD51: SPI DMA seems to leave the SPI peripheral in a freaky
@@ -2089,9 +2089,9 @@ uint16_t Adafruit_SPITFT::readcommand16(uint16_t addr) {
20892089
result = *(volatile uint16_t *)tft8.readPort; // 16-bit read
20902090
*(volatile uint16_t *)tft8.dirSet = 0xFFFF; // Output state
20912091
#else // !HAS_PORT_SET_CLR
2092-
*(volatile uint16_t *)tft8.portDir = 0x0000; // Input state
2093-
result = *(volatile uint16_t *)tft8.readPort; // 16-bit read
2094-
*(volatile uint16_t *)tft8.portDir = 0xFFFF; // Output state
2092+
*(volatile uint16_t *)tft8.portDir = 0x0000; // Input state
2093+
result = *(volatile uint16_t *)tft8.readPort; // 16-bit read
2094+
*(volatile uint16_t *)tft8.portDir = 0xFFFF; // Output state
20952095
#endif // end !HAS_PORT_SET_CLR
20962096
TFT_RD_HIGH(); // Read line HIGH
20972097
endWrite();
@@ -2246,17 +2246,17 @@ uint8_t Adafruit_SPITFT::spiRead(void) {
22462246
w = *tft8.readPort; // Read value from port
22472247
*tft8.portDir = 0xFF; // Restore port to output
22482248
#else // !__AVR__
2249-
if (!tft8.wide) { // 8-bit TFT connection
2249+
if (!tft8.wide) { // 8-bit TFT connection
22502250
#if defined(HAS_PORT_SET_CLR)
2251-
*tft8.dirClr = 0xFF; // Set port to input state
2252-
w = *tft8.readPort; // Read value from port
2253-
*tft8.dirSet = 0xFF; // Restore port to output
2251+
*tft8.dirClr = 0xFF; // Set port to input state
2252+
w = *tft8.readPort; // Read value from port
2253+
*tft8.dirSet = 0xFF; // Restore port to output
22542254
#else // !HAS_PORT_SET_CLR
2255-
*tft8.portDir = 0x00; // Set port to input state
2256-
w = *tft8.readPort; // Read value from port
2257-
*tft8.portDir = 0xFF; // Restore port to output
2255+
*tft8.portDir = 0x00; // Set port to input state
2256+
w = *tft8.readPort; // Read value from port
2257+
*tft8.portDir = 0xFF; // Restore port to output
22582258
#endif // end HAS_PORT_SET_CLR
2259-
} else { // 16-bit TFT connection
2259+
} else { // 16-bit TFT connection
22602260
#if defined(HAS_PORT_SET_CLR)
22612261
*(volatile uint16_t *)tft8.dirClr = 0xFFFF; // Input state
22622262
w = *(volatile uint16_t *)tft8.readPort; // 16-bit read
@@ -2267,7 +2267,7 @@ uint8_t Adafruit_SPITFT::spiRead(void) {
22672267
*(volatile uint16_t *)tft8.portDir = 0xFFFF; // Output state
22682268
#endif // end !HAS_PORT_SET_CLR
22692269
}
2270-
TFT_RD_HIGH(); // Read line HIGH
2270+
TFT_RD_HIGH(); // Read line HIGH
22712271
#endif // end !__AVR__
22722272
#else // !USE_FAST_PINIO
22732273
w = 0; // Parallel TFT is NOT SUPPORTED without USE_FAST_PINIO

Adafruit_SPITFT.h

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@
3232
typedef uint8_t ADAGFX_PORT_t; ///< PORT values are 8-bit
3333
#define USE_FAST_PINIO ///< Use direct PORT register access
3434
#elif defined(ARDUINO_STM32_FEATHER) // WICED
35-
typedef class HardwareSPI SPIClass; ///< SPI is a bit odd on WICED
36-
typedef uint32_t ADAGFX_PORT_t; ///< PORT values are 32-bit
35+
typedef class HardwareSPI SPIClass; ///< SPI is a bit odd on WICED
36+
typedef uint32_t ADAGFX_PORT_t; ///< PORT values are 32-bit
3737
#elif defined(__arm__)
3838
#if defined(ARDUINO_ARCH_SAMD)
3939
// Adafruit M0, M4
@@ -79,8 +79,8 @@ typedef volatile ADAGFX_PORT_t *PORTreg_t; ///< PORT register type
7979
defined(ADAFRUIT_CIRCUITPLAYGROUND_M0)
8080
#define USE_SPI_DMA ///< Auto DMA
8181
#else
82-
//#define USE_SPI_DMA ///< If set,
83-
// use DMA if available
82+
// #define USE_SPI_DMA ///< If set,
83+
// use DMA if available
8484
#endif
8585
// Another "oops" name -- this now also handles parallel DMA.
8686
// If DMA is enabled, Arduino sketch MUST #include <Adafruit_ZeroDMA.h>
@@ -397,8 +397,8 @@ class Adafruit_SPITFT : public Adafruit_GFX {
397397
PORTreg_t dcPortSet; ///< PORT register for data/command SET
398398
PORTreg_t dcPortClr; ///< PORT register for data/command CLEAR
399399
#else // !HAS_PORT_SET_CLR
400-
PORTreg_t csPort; ///< PORT register for chip select
401-
PORTreg_t dcPort; ///< PORT register for data/command
400+
PORTreg_t csPort; ///< PORT register for chip select
401+
PORTreg_t dcPort; ///< PORT register for data/command
402402
#endif // end HAS_PORT_SET_CLR
403403
#endif // end USE_FAST_PINIO
404404
#if defined(__cplusplus) && (__cplusplus >= 201100)
@@ -448,8 +448,8 @@ class Adafruit_SPITFT : public Adafruit_GFX {
448448
volatile uint32_t *writePort; ///< PORT register for DATA WRITE
449449
volatile uint32_t *readPort; ///< PORT (PIN) register for DATA READ
450450
#else
451-
volatile uint8_t *writePort; ///< PORT register for DATA WRITE
452-
volatile uint8_t *readPort; ///< PORT (PIN) register for DATA READ
451+
volatile uint8_t *writePort; ///< PORT register for DATA WRITE
452+
volatile uint8_t *readPort; ///< PORT (PIN) register for DATA READ
453453
#endif
454454
#if defined(HAS_PORT_SET_CLR)
455455
// Port direction register pointers are always 8-bit regardless of
@@ -508,10 +508,10 @@ class Adafruit_SPITFT : public Adafruit_GFX {
508508
ADAGFX_PORT_t dcPinMask; ///< Bitmask for data/command
509509
#endif // end !KINETISK
510510
#else // !HAS_PORT_SET_CLR
511-
ADAGFX_PORT_t csPinMaskSet; ///< Bitmask for chip select SET (OR)
512-
ADAGFX_PORT_t csPinMaskClr; ///< Bitmask for chip select CLEAR (AND)
513-
ADAGFX_PORT_t dcPinMaskSet; ///< Bitmask for data/command SET (OR)
514-
ADAGFX_PORT_t dcPinMaskClr; ///< Bitmask for data/command CLEAR (AND)
511+
ADAGFX_PORT_t csPinMaskSet; ///< Bitmask for chip select SET (OR)
512+
ADAGFX_PORT_t csPinMaskClr; ///< Bitmask for chip select CLEAR (AND)
513+
ADAGFX_PORT_t dcPinMaskSet; ///< Bitmask for data/command SET (OR)
514+
ADAGFX_PORT_t dcPinMaskClr; ///< Bitmask for data/command CLEAR (AND)
515515
#endif // end HAS_PORT_SET_CLR
516516
#endif // end USE_FAST_PINIO
517517
uint8_t connection; ///< TFT_HARD_SPI, TFT_SOFT_SPI, etc.

0 commit comments

Comments
 (0)