some effect optimizations

* getpixelcolor: attribute pure - it reads memory, but does not write
* some optimizations for SEGMENT.blur() and SEGMENT.fadeToBlackBy()

* FX.c:pp remove double calls to blur() and fade_out()
* FX.cpp: SEGMENT.setUpLeds() added to effects, to enable LED buffering (safe some time because getPixelColor does not need to access NeopixelBus)

* a few other optimizations to safe time and avoid "expensive" operations
* set I2C bus speed to 400kHz (default is 100Khz)

* a few other small optimizations and tweaks
* pio: esp32 V4 builds use "patch5" toolchain version, which contains a few bugfixes especially for memory management.
This commit is contained in:
Frank
2023-05-03 20:33:23 +02:00
parent 91d36fa269
commit 7d0e627e14
12 changed files with 66 additions and 31 deletions

View File

@@ -915,7 +915,9 @@ lib_deps = ${esp32_4MB_M_base.lib_deps} ${common_mm.lib_deps_XL}
board = esp32dev board = esp32dev
upload_speed = 460800 ; or 921600 upload_speed = 460800 ; or 921600
platform = ${esp32.platformV4} platform = ${esp32.platformV4}
platform_packages = ${esp32.platformV4_packages} platform_packages =
${esp32.platformV4_packages}
toolchain-xtensa-esp32 @ 8.4.0+2021r2-patch5 ; align main tools with riscV tools
build_unflags = ${common.build_unflags} build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp32.build_flagsV4} ${common_mm.build_flags_S} build_flags = ${common.build_flags} ${esp32.build_flagsV4} ${common_mm.build_flags_S}
-Wno-misleading-indentation -Wno-format-truncation -Wno-misleading-indentation -Wno-format-truncation

View File

@@ -6042,6 +6042,7 @@ uint16_t mode_ripplepeak(void) { // * Ripple peak. By Andrew Tuli
// printUmData(); // printUmData();
if (SEGENV.call == 0) { if (SEGENV.call == 0) {
SEGMENT.setUpLeds();
SEGENV.aux0 = 255; SEGENV.aux0 = 255;
SEGMENT.custom1 = *binNum; SEGMENT.custom1 = *binNum;
SEGMENT.custom2 = *maxVol * 2; SEGMENT.custom2 = *maxVol * 2;
@@ -6052,8 +6053,9 @@ uint16_t mode_ripplepeak(void) { // * Ripple peak. By Andrew Tuli
*binNum = SEGMENT.custom1; // Select a bin. *binNum = SEGMENT.custom1; // Select a bin.
*maxVol = SEGMENT.custom2 / 2; // Our volume comparator. *maxVol = SEGMENT.custom2 / 2; // Our volume comparator.
SEGMENT.fade_out(240); // Lower frame rate means less effective fading than FastLED //SEGMENT.fade_out(240); // Lower frame rate means less effective fading than FastLED
SEGMENT.fade_out(240); //SEGMENT.fade_out(240);
SEGMENT.fade_out(224); // should be the same as 240 applied twice
for (int i = 0; i < SEGMENT.intensity/16; i++) { // Limit the number of ripples. for (int i = 0; i < SEGMENT.intensity/16; i++) { // Limit the number of ripples.
if (samplePeak) ripples[i].state = 255; if (samplePeak) ripples[i].state = 255;
@@ -6066,7 +6068,8 @@ uint16_t mode_ripplepeak(void) { // * Ripple peak. By Andrew Tuli
ripples[i].pos = random16(SEGLEN); ripples[i].pos = random16(SEGLEN);
#ifdef ESP32 #ifdef ESP32
if (FFT_MajorPeak > 1) // log10(0) is "forbidden" (throws exception) if (FFT_MajorPeak > 1) // log10(0) is "forbidden" (throws exception)
ripples[i].color = (int)(log10f(FFT_MajorPeak)*128); //ripples[i].color = (int)(log10f(FFT_MajorPeak)*128); // not to self: buggy !!
ripples[i].color = (int)(logf(FFT_MajorPeak)*32.0f); // works up to 10025 hz
else ripples[i].color = 0; else ripples[i].color = 0;
#else #else
ripples[i].color = random8(); ripples[i].color = random8();
@@ -6476,8 +6479,12 @@ uint16_t mode_midnoise(void) { // Midnoise. By Andrew Tuline.
} }
float volumeSmth = *(float*) um_data->u_data[0]; float volumeSmth = *(float*) um_data->u_data[0];
SEGMENT.fade_out(SEGMENT.speed); if (SEGENV.call == 0) {
SEGMENT.fade_out(SEGMENT.speed); SEGMENT.setUpLeds();
SEGMENT.fill(BLACK);
}
SEGMENT.fadeToBlackBy(SEGMENT.speed/2);
//SEGMENT.fade_out(SEGMENT.speed);
float tmpSound2 = volumeSmth * (float)SEGMENT.intensity / 256.0; // Too sensitive. float tmpSound2 = volumeSmth * (float)SEGMENT.intensity / 256.0; // Too sensitive.
tmpSound2 *= (float)SEGMENT.intensity / 128.0; // Reduce sensitity/length. tmpSound2 *= (float)SEGMENT.intensity / 128.0; // Reduce sensitity/length.
@@ -6622,8 +6629,13 @@ uint16_t mode_plasmoid(void) { // Plasmoid. By Andrew Tuline.
} }
float volumeSmth = *(float*) um_data->u_data[0]; float volumeSmth = *(float*) um_data->u_data[0];
SEGMENT.fadeToBlackBy(32); if (SEGENV.call == 0) {
SEGMENT.setUpLeds();
SEGMENT.fill(BLACK);
}
//SEGMENT.fadeToBlackBy(32);
SEGMENT.fadeToBlackBy(48);
plasmoip->thisphase += beatsin8(6,-4,4); // You can change direction and speed individually. plasmoip->thisphase += beatsin8(6,-4,4); // You can change direction and speed individually.
plasmoip->thatphase += beatsin8(7,-4,4); // Two phase values to make a complex pattern. By Andrew Tuline. plasmoip->thatphase += beatsin8(7,-4,4); // Two phase values to make a complex pattern. By Andrew Tuline.
@@ -6921,7 +6933,10 @@ uint16_t mode_freqmap(void) { // Map FFT_MajorPeak to SEGLEN.
float my_magnitude = *(float*)um_data->u_data[5] / 4.0f; float my_magnitude = *(float*)um_data->u_data[5] / 4.0f;
if (FFT_MajorPeak < 1) FFT_MajorPeak = 1; // log10(0) is "forbidden" (throws exception) if (FFT_MajorPeak < 1) FFT_MajorPeak = 1; // log10(0) is "forbidden" (throws exception)
if (SEGENV.call == 0) SEGMENT.fill(BLACK); if (SEGENV.call == 0) {
SEGMENT.setUpLeds();
SEGMENT.fill(BLACK);
}
int fadeoutDelay = (256 - SEGMENT.speed) / 32; int fadeoutDelay = (256 - SEGMENT.speed) / 32;
if ((fadeoutDelay <= 1 ) || ((SEGENV.call % fadeoutDelay) == 0)) SEGMENT.fade_out(SEGMENT.speed); if ((fadeoutDelay <= 1 ) || ((SEGENV.call % fadeoutDelay) == 0)) SEGMENT.fade_out(SEGMENT.speed);
@@ -7068,7 +7083,7 @@ uint16_t mode_freqwave(void) { // Freqwave. By Andreas Pleschun
SEGMENT.fill(BLACK); SEGMENT.fill(BLACK);
} }
uint8_t secondHand = micros()/(256-SEGMENT.speed)/500 % 16; uint8_t secondHand = (SEGMENT.speed < 255) ? (micros()/(256-SEGMENT.speed)/500 % 16) : 0;
if((SEGMENT.speed > 254) || (SEGENV.aux0 != secondHand)) { // WLEDMM allow to run at full speed if((SEGMENT.speed > 254) || (SEGENV.aux0 != secondHand)) { // WLEDMM allow to run at full speed
SEGENV.aux0 = secondHand; SEGENV.aux0 = secondHand;

View File

@@ -571,7 +571,7 @@ typedef struct Segment {
void setPixelColor(float i, uint32_t c, bool aa = true); void setPixelColor(float i, uint32_t c, bool aa = true);
void setPixelColor(float i, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0, bool aa = true) { setPixelColor(i, RGBW32(r,g,b,w), aa); } void setPixelColor(float i, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0, bool aa = true) { setPixelColor(i, RGBW32(r,g,b,w), aa); }
void setPixelColor(float i, CRGB c, bool aa = true) { setPixelColor(i, RGBW32(c.r,c.g,c.b,0), aa); } void setPixelColor(float i, CRGB c, bool aa = true) { setPixelColor(i, RGBW32(c.r,c.g,c.b,0), aa); }
uint32_t getPixelColor(int i); uint32_t __attribute__((pure)) getPixelColor(int i); // WLEDMM attribute added
// 1D support functions (some implement 2D as well) // 1D support functions (some implement 2D as well)
void blur(uint8_t); void blur(uint8_t);
void fill(uint32_t c); void fill(uint32_t c);
@@ -594,14 +594,14 @@ typedef struct Segment {
void createjMap(); //WLEDMM jMap void createjMap(); //WLEDMM jMap
void deletejMap(); //WLEDMM jMap void deletejMap(); //WLEDMM jMap
#ifndef WLED_DISABLE_2D #ifndef WLED_DISABLE_2D
uint16_t XY(uint16_t x, uint16_t y); // support function to get relative index within segment (for leds[]) uint16_t __attribute__((pure)) XY(uint16_t x, uint16_t y); // support function to get relative index within segment (for leds[]) // WLEDMM attribute pure
void setPixelColorXY(int x, int y, uint32_t c); // set relative pixel within segment with color void setPixelColorXY(int x, int y, uint32_t c); // set relative pixel within segment with color
void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColorXY(x, y, RGBW32(r,g,b,w)); } // automatically inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColorXY(x, y, RGBW32(r,g,b,w)); } // automatically inline
void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); } // automatically inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); } // automatically inline
void setPixelColorXY(float x, float y, uint32_t c, bool aa = true, bool fast = true); void setPixelColorXY(float x, float y, uint32_t c, bool aa = true, bool fast = true);
void setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = true) { setPixelColorXY(x, y, RGBW32(r,g,b,w), aa); } void setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = true) { setPixelColorXY(x, y, RGBW32(r,g,b,w), aa); }
void setPixelColorXY(float x, float y, CRGB c, bool aa = true) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), aa); } void setPixelColorXY(float x, float y, CRGB c, bool aa = true) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), aa); }
uint32_t getPixelColorXY(uint16_t x, uint16_t y); uint32_t __attribute__((pure)) getPixelColorXY(uint16_t x, uint16_t y); // WLEDMM attribute pure
// 2D support functions // 2D support functions
void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend); void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend);
void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), blend); } void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), blend); }

View File

@@ -1132,14 +1132,14 @@ void Segment::fade_out(uint8_t rate) {
uint_fast8_t fadeRate = (255-rate) >> 1; uint_fast8_t fadeRate = (255-rate) >> 1;
float mappedRate_r = 1.0f / (float(fadeRate) +1.1f); // WLEDMM use reciprocal 1/mappedRate -> faster on non-FPU chips float mappedRate_r = 1.0f / (float(fadeRate) +1.1f); // WLEDMM use reciprocal 1/mappedRate -> faster on non-FPU chips
uint32_t color = colors[1]; // SEGCOLOR(1); // target color uint32_t color2 = colors[1]; // SEGCOLOR(1); // target color // WLEDMM minor optimization
int w2 = W(color); int w2 = W(color2);
int r2 = R(color); int r2 = R(color2);
int g2 = G(color); int g2 = G(color2);
int b2 = B(color); int b2 = B(color2);
for (uint_fast16_t y = 0; y < rows; y++) for (uint_fast16_t x = 0; x < cols; x++) { for (uint_fast16_t y = 0; y < rows; y++) for (uint_fast16_t x = 0; x < cols; x++) {
color = is2D() ? getPixelColorXY(x, y) : getPixelColor(x); uint32_t color = is2D() ? getPixelColorXY(x, y) : getPixelColor(x);
int w1 = W(color); int w1 = W(color);
int r1 = R(color); int r1 = R(color);
int g1 = G(color); int g1 = G(color);
@@ -1156,6 +1156,7 @@ void Segment::fade_out(uint8_t rate) {
gdelta += (g2 == g1) ? 0 : (g2 > g1) ? 1 : -1; gdelta += (g2 == g1) ? 0 : (g2 > g1) ? 1 : -1;
bdelta += (b2 == b1) ? 0 : (b2 > b1) ? 1 : -1; bdelta += (b2 == b1) ? 0 : (b2 > b1) ? 1 : -1;
//if ((wdelta == 0) && (rdelta == 0) && (gdelta == 0) && (bdelta == 0)) continue; // WLEDMM delta = zero => no change // causes problem with text overlay
if (is2D()) setPixelColorXY((uint16_t)x, (uint16_t)y, r1 + rdelta, g1 + gdelta, b1 + bdelta, w1 + wdelta); if (is2D()) setPixelColorXY((uint16_t)x, (uint16_t)y, r1 + rdelta, g1 + gdelta, b1 + bdelta, w1 + wdelta);
else setPixelColor((uint16_t)x, r1 + rdelta, g1 + gdelta, b1 + bdelta, w1 + wdelta); else setPixelColor((uint16_t)x, r1 + rdelta, g1 + gdelta, b1 + bdelta, w1 + wdelta);
} }
@@ -1167,9 +1168,15 @@ void Segment::fadeToBlackBy(uint8_t fadeBy) {
const uint_fast16_t rows = virtualHeight(); // will be 1 for 1D const uint_fast16_t rows = virtualHeight(); // will be 1 for 1D
const uint_fast8_t scaledown = 255-fadeBy; // WLEDMM faster to pre-compute this const uint_fast8_t scaledown = 255-fadeBy; // WLEDMM faster to pre-compute this
for (uint_fast16_t y = 0; y < rows; y++) for (uint_fast16_t x = 0; x < cols; x++) { // WLEDMM minor optimization
if (is2D()) setPixelColorXY((uint16_t)x, (uint16_t)y, CRGB(getPixelColorXY(x,y)).nscale8(scaledown)); if(is2D()) {
else setPixelColor((uint16_t)x, CRGB(getPixelColor(x)).nscale8(scaledown)); for (uint_fast16_t y = 0; y < rows; y++) for (uint_fast16_t x = 0; x < cols; x++) {
setPixelColorXY((uint16_t)x, (uint16_t)y, CRGB(getPixelColorXY(x,y)).nscale8(scaledown));
}
} else {
for (uint_fast16_t x = 0; x < cols; x++) {
setPixelColor((uint16_t)x, CRGB(getPixelColor((uint16_t)x)).nscale8(scaledown));
}
} }
} }
@@ -1196,6 +1203,7 @@ void Segment::blur(uint8_t blur_amount)
{ {
CRGB cur = CRGB(getPixelColor(i)); CRGB cur = CRGB(getPixelColor(i));
CRGB part = cur; CRGB part = cur;
CRGB before = cur; // WLEDMM
part.nscale8(seep); part.nscale8(seep);
cur.nscale8(keep); cur.nscale8(keep);
cur += carryover; cur += carryover;
@@ -1206,7 +1214,8 @@ void Segment::blur(uint8_t blur_amount)
uint8_t b = B(c); uint8_t b = B(c);
setPixelColor((uint16_t)(i-1), qadd8(r, part.red), qadd8(g, part.green), qadd8(b, part.blue)); setPixelColor((uint16_t)(i-1), qadd8(r, part.red), qadd8(g, part.green), qadd8(b, part.blue));
} }
setPixelColor((uint16_t)i,cur.red, cur.green, cur.blue); if (before != cur) // WLEDMM optimization: don't write same color again
setPixelColor((uint16_t)i,cur.red, cur.green, cur.blue);
carryover = part; carryover = part;
} }
} }

View File

@@ -420,7 +420,9 @@ BusNetwork::BusNetwork(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) {
void BusNetwork::setPixelColor(uint16_t pix, uint32_t c) { void BusNetwork::setPixelColor(uint16_t pix, uint32_t c) {
if (!_valid || pix >= _len) return; if (!_valid || pix >= _len) return;
if (hasWhite()) c = autoWhiteCalc(c); if (hasWhite()) c = autoWhiteCalc(c);
#if !defined(WLEDMM_FASTPATH) // WLEDMM expensive operation
if (_cct >= 1900) c = colorBalanceFromKelvin(_cct, c); //color correction from CCT if (_cct >= 1900) c = colorBalanceFromKelvin(_cct, c); //color correction from CCT
#endif
uint16_t offset = pix * _UDPchannels; uint16_t offset = pix * _UDPchannels;
_data[offset] = R(c); _data[offset] = R(c);
_data[offset+1] = G(c); _data[offset+1] = G(c);

View File

@@ -288,7 +288,7 @@ class BusNetwork : public Bus {
void setPixelColor(uint16_t pix, uint32_t c); void setPixelColor(uint16_t pix, uint32_t c);
uint32_t getPixelColor(uint16_t pix); uint32_t __attribute__((pure)) getPixelColor(uint16_t pix); // WLEDMM attribute added
void show(); void show();
@@ -341,7 +341,7 @@ class BusManager {
void setSegmentCCT(int16_t cct, bool allowWBCorrection = false); void setSegmentCCT(int16_t cct, bool allowWBCorrection = false);
uint32_t getPixelColor(uint_fast16_t pix); uint32_t __attribute__((pure)) getPixelColor(uint_fast16_t pix); // WLEDMM attribute added
bool canAllShow(); bool canAllShow();

View File

@@ -11,7 +11,7 @@ IRAM_ATTR_YN uint32_t color_blend(uint32_t color1, uint32_t color2, uint_fast16_
if(blend == 0) return color1; if(blend == 0) return color1;
uint_fast16_t blendmax = b16 ? 0xFFFF : 0xFF; uint_fast16_t blendmax = b16 ? 0xFFFF : 0xFF;
if(blend == blendmax) return color2; if(blend == blendmax) return color2;
uint_fast8_t shift = b16 ? 16 : 8; const uint_fast8_t shift = b16 ? 16 : 8;
uint32_t w1 = W(color1); uint32_t w1 = W(color1);
uint32_t r1 = R(color1); uint32_t r1 = R(color1);

View File

@@ -88,7 +88,9 @@ void _overlayAnalogCountdown()
} }
void handleOverlayDraw() { void handleOverlayDraw() {
#if !defined(WLEDMM_FASTPATH) // WLEDMM expensive operation, and most usermods don't draw overlays
usermods.handleOverlayDraw(); usermods.handleOverlayDraw();
#endif
if (overlayCurrent == 1) _overlayAnalogClock(); if (overlayCurrent == 1) _overlayAnalogClock();
} }

View File

@@ -588,7 +588,11 @@ bool PinManagerClass::joinWire(int8_t pinSDA, int8_t pinSCL) {
} }
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
#if defined(WLEDMM_FASTPATH) // wledMM set I2C to 400Khz, to minimize I2C communication delays
wireIsOK = Wire.begin(pinSDA, pinSCL, 400000UL); // this will fail if wire is already running
#else
wireIsOK = Wire.begin(pinSDA, pinSCL); // this will fail if wire is already running wireIsOK = Wire.begin(pinSDA, pinSCL); // this will fail if wire is already running
#endif
#else #else
Wire.begin(pinSDA, pinSCL); // returns void on 8266 Wire.begin(pinSDA, pinSCL); // returns void on 8266
#endif #endif

View File

@@ -232,11 +232,12 @@ void handleNotifications()
if (!udpConnected) return; if (!udpConnected) return;
bool isSupp = false; bool isSupp = false;
size_t packetSize = notifierUdp.parsePacket(); int packetSize = notifierUdp.parsePacket(); // WLEDMM function returns int, not size_t
if (!packetSize && udp2Connected) { if ((packetSize < 1) && udp2Connected) {
packetSize = notifier2Udp.parsePacket(); packetSize = notifier2Udp.parsePacket();
isSupp = true; isSupp = true;
} }
if (packetSize < 1) packetSize = 0; // WLEDMM
//hyperion / raw RGB //hyperion / raw RGB
if (!packetSize && udpRgbConnected) { if (!packetSize && udpRgbConnected) {

View File

@@ -8,7 +8,7 @@
*/ */
// version code in format yymmddb (b = daily build) // version code in format yymmddb (b = daily build)
#define VERSION 2304300 #define VERSION 2305030
//uncomment this if you have a "my_config.h" file you'd like to use //uncomment this if you have a "my_config.h" file you'd like to use
//#define WLED_USE_MY_CONFIG //#define WLED_USE_MY_CONFIG

View File

@@ -185,8 +185,8 @@ static bool sendLiveLedsWs(uint32_t wsClient) // WLEDMM added "static"
#ifndef WLED_DISABLE_2D #ifndef WLED_DISABLE_2D
if (strip.isMatrix) { if (strip.isMatrix) {
buffer[1] = 2; //version buffer[1] = 2; //version
buffer[2] = Segment::maxWidth; buffer[2] = min(Segment::maxWidth, (uint16_t) 255); // WLEDMM prevent overflow
buffer[3] = Segment::maxHeight; buffer[3] = min(Segment::maxHeight, (uint16_t) 255);
//WLEDMM: no skipLines //WLEDMM: no skipLines
} }
#endif #endif