mirror of
https://github.com/adafruit/Adafruit-GFX-Library.git
synced 2026-07-28 04:16:01 +00:00
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
This commit is contained in:
+42
-16
@@ -1758,12 +1758,21 @@ const uint8_t PROGMEM GFXcanvas1::GFXclrBit[] = {0x7F, 0xBF, 0xDF, 0xEF,
|
||||
@brief Instatiate a GFX 1-bit canvas context for graphics
|
||||
@param w Display width, in pixels
|
||||
@param h Display height, in pixels
|
||||
@param allocate_buffer If true, a buffer is allocated with malloc. If
|
||||
false, the subclass must initialize the buffer before any drawing operation,
|
||||
and free it in the destructor. If false (the default), the buffer is
|
||||
allocated and freed by the library.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
GFXcanvas1::GFXcanvas1(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) {
|
||||
uint32_t bytes = ((w + 7) / 8) * h;
|
||||
if ((buffer = (uint8_t *)malloc(bytes))) {
|
||||
memset(buffer, 0, bytes);
|
||||
GFXcanvas1::GFXcanvas1(uint16_t w, uint16_t h, bool allocate_buffer)
|
||||
: Adafruit_GFX(w, h), buffer_owned(allocate_buffer) {
|
||||
if (allocate_buffer) {
|
||||
uint32_t bytes = ((w + 7) / 8) * h;
|
||||
if ((buffer = (uint8_t *)malloc(bytes))) {
|
||||
memset(buffer, 0, bytes);
|
||||
}
|
||||
} else {
|
||||
buffer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1773,7 +1782,7 @@ GFXcanvas1::GFXcanvas1(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) {
|
||||
*/
|
||||
/**************************************************************************/
|
||||
GFXcanvas1::~GFXcanvas1(void) {
|
||||
if (buffer)
|
||||
if (buffer && buffer_owned)
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
@@ -2111,13 +2120,21 @@ void GFXcanvas1::drawFastRawHLine(int16_t x, int16_t y, int16_t w,
|
||||
@brief Instatiate a GFX 8-bit canvas context for graphics
|
||||
@param w Display width, in pixels
|
||||
@param h Display height, in pixels
|
||||
@param allocate_buffer If true, a buffer is allocated with malloc. If
|
||||
false, the subclass must initialize the buffer before any drawing operation,
|
||||
and free it in the destructor. If false (the default), the buffer is
|
||||
allocated and freed by the library.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
GFXcanvas8::GFXcanvas8(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) {
|
||||
uint32_t bytes = w * h;
|
||||
if ((buffer = (uint8_t *)malloc(bytes))) {
|
||||
memset(buffer, 0, bytes);
|
||||
}
|
||||
GFXcanvas8::GFXcanvas8(uint16_t w, uint16_t h, bool allocate_buffer)
|
||||
: Adafruit_GFX(w, h), buffer_owned(allocate_buffer) {
|
||||
if (allocate_buffer) {
|
||||
uint32_t bytes = w * h;
|
||||
if ((buffer = (uint8_t *)malloc(bytes))) {
|
||||
memset(buffer, 0, bytes);
|
||||
}
|
||||
} else
|
||||
buffer = nullptr;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
@@ -2126,7 +2143,7 @@ GFXcanvas8::GFXcanvas8(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) {
|
||||
*/
|
||||
/**************************************************************************/
|
||||
GFXcanvas8::~GFXcanvas8(void) {
|
||||
if (buffer)
|
||||
if (buffer && buffer_owned)
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
@@ -2379,12 +2396,21 @@ void GFXcanvas8::drawFastRawHLine(int16_t x, int16_t y, int16_t w,
|
||||
@brief Instatiate a GFX 16-bit canvas context for graphics
|
||||
@param w Display width, in pixels
|
||||
@param h Display height, in pixels
|
||||
@param allocate_buffer If true, a buffer is allocated with malloc. If
|
||||
false, the subclass must initialize the buffer before any drawing operation,
|
||||
and free it in the destructor. If false (the default), the buffer is
|
||||
allocated and freed by the library.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
GFXcanvas16::GFXcanvas16(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) {
|
||||
uint32_t bytes = w * h * 2;
|
||||
if ((buffer = (uint16_t *)malloc(bytes))) {
|
||||
memset(buffer, 0, bytes);
|
||||
GFXcanvas16::GFXcanvas16(uint16_t w, uint16_t h, bool allocate_buffer)
|
||||
: Adafruit_GFX(w, h), buffer_owned(allocate_buffer) {
|
||||
if (allocate_buffer) {
|
||||
uint32_t bytes = w * h * 2;
|
||||
if ((buffer = (uint16_t *)malloc(bytes))) {
|
||||
memset(buffer, 0, bytes);
|
||||
}
|
||||
} else {
|
||||
buffer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2394,7 +2420,7 @@ GFXcanvas16::GFXcanvas16(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) {
|
||||
*/
|
||||
/**************************************************************************/
|
||||
GFXcanvas16::~GFXcanvas16(void) {
|
||||
if (buffer)
|
||||
if (buffer && buffer_owned)
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
|
||||
+12
-6
@@ -309,7 +309,7 @@ private:
|
||||
/// A GFX 1-bit canvas context for graphics
|
||||
class GFXcanvas1 : public Adafruit_GFX {
|
||||
public:
|
||||
GFXcanvas1(uint16_t w, uint16_t h);
|
||||
GFXcanvas1(uint16_t w, uint16_t h, bool allocate_buffer = true);
|
||||
~GFXcanvas1(void);
|
||||
void drawPixel(int16_t x, int16_t y, uint16_t color);
|
||||
void fillScreen(uint16_t color);
|
||||
@@ -328,7 +328,9 @@ protected:
|
||||
bool getRawPixel(int16_t x, int16_t y) const;
|
||||
void drawFastRawVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
|
||||
void drawFastRawHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
|
||||
uint8_t *buffer; ///< Raster data: no longer private, allow subclass access
|
||||
uint8_t *buffer; ///< Raster data: no longer private, allow subclass access
|
||||
bool buffer_owned; ///< If true, destructor will free buffer, else it will do
|
||||
///< nothing
|
||||
|
||||
private:
|
||||
#ifdef __AVR__
|
||||
@@ -340,7 +342,7 @@ private:
|
||||
/// A GFX 8-bit canvas context for graphics
|
||||
class GFXcanvas8 : public Adafruit_GFX {
|
||||
public:
|
||||
GFXcanvas8(uint16_t w, uint16_t h);
|
||||
GFXcanvas8(uint16_t w, uint16_t h, bool allocate_buffer = true);
|
||||
~GFXcanvas8(void);
|
||||
void drawPixel(int16_t x, int16_t y, uint16_t color);
|
||||
void fillScreen(uint16_t color);
|
||||
@@ -359,13 +361,15 @@ protected:
|
||||
uint8_t getRawPixel(int16_t x, int16_t y) const;
|
||||
void drawFastRawVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
|
||||
void drawFastRawHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
|
||||
uint8_t *buffer; ///< Raster data: no longer private, allow subclass access
|
||||
uint8_t *buffer; ///< Raster data: no longer private, allow subclass access
|
||||
bool buffer_owned; ///< If true, destructor will free buffer, else it will do
|
||||
///< nothing
|
||||
};
|
||||
|
||||
/// A GFX 16-bit canvas context for graphics
|
||||
class GFXcanvas16 : public Adafruit_GFX {
|
||||
public:
|
||||
GFXcanvas16(uint16_t w, uint16_t h);
|
||||
GFXcanvas16(uint16_t w, uint16_t h, bool allocate_buffer = true);
|
||||
~GFXcanvas16(void);
|
||||
void drawPixel(int16_t x, int16_t y, uint16_t color);
|
||||
void fillScreen(uint16_t color);
|
||||
@@ -385,7 +389,9 @@ protected:
|
||||
uint16_t getRawPixel(int16_t x, int16_t y) const;
|
||||
void drawFastRawVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
|
||||
void drawFastRawHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
|
||||
uint16_t *buffer; ///< Raster data: no longer private, allow subclass access
|
||||
uint16_t *buffer; ///< Raster data: no longer private, allow subclass access
|
||||
bool buffer_owned; ///< If true, destructor will free buffer, else it will do
|
||||
///< nothing
|
||||
};
|
||||
|
||||
#endif // _ADAFRUIT_GFX_H
|
||||
|
||||
+23
-23
@@ -879,7 +879,7 @@ void Adafruit_SPITFT::initSPI(uint32_t freq, uint8_t spiMode) {
|
||||
DMA_ADDRESS_INCREMENT_STEP_SIZE_1;
|
||||
descriptor[d].DSTADDR.reg = (uint32_t)tft8.writePort;
|
||||
}
|
||||
#endif // __SAMD51
|
||||
#endif // __SAMD51
|
||||
} // end parallel-specific DMA setup
|
||||
|
||||
lastFillColor = 0x0000;
|
||||
@@ -887,13 +887,13 @@ void Adafruit_SPITFT::initSPI(uint32_t freq, uint8_t spiMode) {
|
||||
dma.setCallback(dma_callback);
|
||||
return; // Success!
|
||||
// else clean up any partial allocation...
|
||||
} // end descriptor memalign()
|
||||
} // end descriptor memalign()
|
||||
free(pixelBuf[0]);
|
||||
pixelBuf[0] = pixelBuf[1] = NULL;
|
||||
} // end pixelBuf malloc()
|
||||
// Don't currently have a descriptor delete function in
|
||||
// ZeroDMA lib, but if we did, it would be called here.
|
||||
} // end addDescriptor()
|
||||
} // end pixelBuf malloc()
|
||||
// Don't currently have a descriptor delete function in
|
||||
// ZeroDMA lib, but if we did, it would be called here.
|
||||
} // end addDescriptor()
|
||||
dma.free(); // Deallocate DMA channel
|
||||
}
|
||||
#endif // end USE_SPI_DMA
|
||||
@@ -1373,11 +1373,11 @@ void Adafruit_SPITFT::writeColor(uint16_t color, uint32_t len) {
|
||||
dma.trigger();
|
||||
while (dma_busy)
|
||||
; // Wait for completion
|
||||
// Unfortunately blocking is necessary. An earlier version returned
|
||||
// immediately and checked dma_busy on startWrite() instead, but it
|
||||
// turns out to be MUCH slower on many graphics operations (as when
|
||||
// drawing lines, pixel-by-pixel), perhaps because it's a volatile
|
||||
// type and doesn't cache. Working on this.
|
||||
// Unfortunately blocking is necessary. An earlier version returned
|
||||
// immediately and checked dma_busy on startWrite() instead, but it
|
||||
// turns out to be MUCH slower on many graphics operations (as when
|
||||
// drawing lines, pixel-by-pixel), perhaps because it's a volatile
|
||||
// type and doesn't cache. Working on this.
|
||||
#if defined(__SAMD51__) || defined(ARDUINO_SAMD_ZERO)
|
||||
if (connection == TFT_HARD_SPI) {
|
||||
// SAMD51: SPI DMA seems to leave the SPI peripheral in a freaky
|
||||
@@ -2089,9 +2089,9 @@ uint16_t Adafruit_SPITFT::readcommand16(uint16_t addr) {
|
||||
result = *(volatile uint16_t *)tft8.readPort; // 16-bit read
|
||||
*(volatile uint16_t *)tft8.dirSet = 0xFFFF; // Output state
|
||||
#else // !HAS_PORT_SET_CLR
|
||||
*(volatile uint16_t *)tft8.portDir = 0x0000; // Input state
|
||||
result = *(volatile uint16_t *)tft8.readPort; // 16-bit read
|
||||
*(volatile uint16_t *)tft8.portDir = 0xFFFF; // Output state
|
||||
*(volatile uint16_t *)tft8.portDir = 0x0000; // Input state
|
||||
result = *(volatile uint16_t *)tft8.readPort; // 16-bit read
|
||||
*(volatile uint16_t *)tft8.portDir = 0xFFFF; // Output state
|
||||
#endif // end !HAS_PORT_SET_CLR
|
||||
TFT_RD_HIGH(); // Read line HIGH
|
||||
endWrite();
|
||||
@@ -2246,17 +2246,17 @@ uint8_t Adafruit_SPITFT::spiRead(void) {
|
||||
w = *tft8.readPort; // Read value from port
|
||||
*tft8.portDir = 0xFF; // Restore port to output
|
||||
#else // !__AVR__
|
||||
if (!tft8.wide) { // 8-bit TFT connection
|
||||
if (!tft8.wide) { // 8-bit TFT connection
|
||||
#if defined(HAS_PORT_SET_CLR)
|
||||
*tft8.dirClr = 0xFF; // Set port to input state
|
||||
w = *tft8.readPort; // Read value from port
|
||||
*tft8.dirSet = 0xFF; // Restore port to output
|
||||
*tft8.dirClr = 0xFF; // Set port to input state
|
||||
w = *tft8.readPort; // Read value from port
|
||||
*tft8.dirSet = 0xFF; // Restore port to output
|
||||
#else // !HAS_PORT_SET_CLR
|
||||
*tft8.portDir = 0x00; // Set port to input state
|
||||
w = *tft8.readPort; // Read value from port
|
||||
*tft8.portDir = 0xFF; // Restore port to output
|
||||
*tft8.portDir = 0x00; // Set port to input state
|
||||
w = *tft8.readPort; // Read value from port
|
||||
*tft8.portDir = 0xFF; // Restore port to output
|
||||
#endif // end HAS_PORT_SET_CLR
|
||||
} else { // 16-bit TFT connection
|
||||
} else { // 16-bit TFT connection
|
||||
#if defined(HAS_PORT_SET_CLR)
|
||||
*(volatile uint16_t *)tft8.dirClr = 0xFFFF; // Input state
|
||||
w = *(volatile uint16_t *)tft8.readPort; // 16-bit read
|
||||
@@ -2267,7 +2267,7 @@ uint8_t Adafruit_SPITFT::spiRead(void) {
|
||||
*(volatile uint16_t *)tft8.portDir = 0xFFFF; // Output state
|
||||
#endif // end !HAS_PORT_SET_CLR
|
||||
}
|
||||
TFT_RD_HIGH(); // Read line HIGH
|
||||
TFT_RD_HIGH(); // Read line HIGH
|
||||
#endif // end !__AVR__
|
||||
#else // !USE_FAST_PINIO
|
||||
w = 0; // Parallel TFT is NOT SUPPORTED without USE_FAST_PINIO
|
||||
|
||||
+12
-12
@@ -32,8 +32,8 @@
|
||||
typedef uint8_t ADAGFX_PORT_t; ///< PORT values are 8-bit
|
||||
#define USE_FAST_PINIO ///< Use direct PORT register access
|
||||
#elif defined(ARDUINO_STM32_FEATHER) // WICED
|
||||
typedef class HardwareSPI SPIClass; ///< SPI is a bit odd on WICED
|
||||
typedef uint32_t ADAGFX_PORT_t; ///< PORT values are 32-bit
|
||||
typedef class HardwareSPI SPIClass; ///< SPI is a bit odd on WICED
|
||||
typedef uint32_t ADAGFX_PORT_t; ///< PORT values are 32-bit
|
||||
#elif defined(__arm__)
|
||||
#if defined(ARDUINO_ARCH_SAMD)
|
||||
// Adafruit M0, M4
|
||||
@@ -79,8 +79,8 @@ typedef volatile ADAGFX_PORT_t *PORTreg_t; ///< PORT register type
|
||||
defined(ADAFRUIT_CIRCUITPLAYGROUND_M0)
|
||||
#define USE_SPI_DMA ///< Auto DMA
|
||||
#else
|
||||
//#define USE_SPI_DMA ///< If set,
|
||||
// use DMA if available
|
||||
// #define USE_SPI_DMA ///< If set,
|
||||
// use DMA if available
|
||||
#endif
|
||||
// Another "oops" name -- this now also handles parallel DMA.
|
||||
// If DMA is enabled, Arduino sketch MUST #include <Adafruit_ZeroDMA.h>
|
||||
@@ -397,8 +397,8 @@ protected:
|
||||
PORTreg_t dcPortSet; ///< PORT register for data/command SET
|
||||
PORTreg_t dcPortClr; ///< PORT register for data/command CLEAR
|
||||
#else // !HAS_PORT_SET_CLR
|
||||
PORTreg_t csPort; ///< PORT register for chip select
|
||||
PORTreg_t dcPort; ///< PORT register for data/command
|
||||
PORTreg_t csPort; ///< PORT register for chip select
|
||||
PORTreg_t dcPort; ///< PORT register for data/command
|
||||
#endif // end HAS_PORT_SET_CLR
|
||||
#endif // end USE_FAST_PINIO
|
||||
#if defined(__cplusplus) && (__cplusplus >= 201100)
|
||||
@@ -448,8 +448,8 @@ protected:
|
||||
volatile uint32_t *writePort; ///< PORT register for DATA WRITE
|
||||
volatile uint32_t *readPort; ///< PORT (PIN) register for DATA READ
|
||||
#else
|
||||
volatile uint8_t *writePort; ///< PORT register for DATA WRITE
|
||||
volatile uint8_t *readPort; ///< PORT (PIN) register for DATA READ
|
||||
volatile uint8_t *writePort; ///< PORT register for DATA WRITE
|
||||
volatile uint8_t *readPort; ///< PORT (PIN) register for DATA READ
|
||||
#endif
|
||||
#if defined(HAS_PORT_SET_CLR)
|
||||
// Port direction register pointers are always 8-bit regardless of
|
||||
@@ -508,10 +508,10 @@ protected:
|
||||
ADAGFX_PORT_t dcPinMask; ///< Bitmask for data/command
|
||||
#endif // end !KINETISK
|
||||
#else // !HAS_PORT_SET_CLR
|
||||
ADAGFX_PORT_t csPinMaskSet; ///< Bitmask for chip select SET (OR)
|
||||
ADAGFX_PORT_t csPinMaskClr; ///< Bitmask for chip select CLEAR (AND)
|
||||
ADAGFX_PORT_t dcPinMaskSet; ///< Bitmask for data/command SET (OR)
|
||||
ADAGFX_PORT_t dcPinMaskClr; ///< Bitmask for data/command CLEAR (AND)
|
||||
ADAGFX_PORT_t csPinMaskSet; ///< Bitmask for chip select SET (OR)
|
||||
ADAGFX_PORT_t csPinMaskClr; ///< Bitmask for chip select CLEAR (AND)
|
||||
ADAGFX_PORT_t dcPinMaskSet; ///< Bitmask for data/command SET (OR)
|
||||
ADAGFX_PORT_t dcPinMaskClr; ///< Bitmask for data/command CLEAR (AND)
|
||||
#endif // end HAS_PORT_SET_CLR
|
||||
#endif // end USE_FAST_PINIO
|
||||
uint8_t connection; ///< TFT_HARD_SPI, TFT_SOFT_SPI, etc.
|
||||
|
||||
Reference in New Issue
Block a user