From 7d0e627e14179061640ba777c59bb7d54ba1fbb0 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Wed, 3 May 2023 20:33:23 +0200 Subject: [PATCH] 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. --- platformio.ini | 4 +++- wled00/FX.cpp | 33 ++++++++++++++++++++++++--------- wled00/FX.h | 6 +++--- wled00/FX_fcn.cpp | 29 +++++++++++++++++++---------- wled00/bus_manager.cpp | 2 ++ wled00/bus_manager.h | 4 ++-- wled00/colors.cpp | 2 +- wled00/overlay.cpp | 2 ++ wled00/pin_manager.cpp | 4 ++++ wled00/udp.cpp | 5 +++-- wled00/wled.h | 2 +- wled00/ws.cpp | 4 ++-- 12 files changed, 66 insertions(+), 31 deletions(-) diff --git a/platformio.ini b/platformio.ini index aa146b13..c80de4cf 100644 --- a/platformio.ini +++ b/platformio.ini @@ -915,7 +915,9 @@ lib_deps = ${esp32_4MB_M_base.lib_deps} ${common_mm.lib_deps_XL} board = esp32dev upload_speed = 460800 ; or 921600 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_flags = ${common.build_flags} ${esp32.build_flagsV4} ${common_mm.build_flags_S} -Wno-misleading-indentation -Wno-format-truncation diff --git a/wled00/FX.cpp b/wled00/FX.cpp index d36bac0c..6f259df9 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -6042,6 +6042,7 @@ uint16_t mode_ripplepeak(void) { // * Ripple peak. By Andrew Tuli // printUmData(); if (SEGENV.call == 0) { + SEGMENT.setUpLeds(); SEGENV.aux0 = 255; SEGMENT.custom1 = *binNum; SEGMENT.custom2 = *maxVol * 2; @@ -6052,8 +6053,9 @@ uint16_t mode_ripplepeak(void) { // * Ripple peak. By Andrew Tuli *binNum = SEGMENT.custom1; // Select a bin. *maxVol = SEGMENT.custom2 / 2; // Our volume comparator. - SEGMENT.fade_out(240); // Lower frame rate means less effective fading than FastLED - SEGMENT.fade_out(240); + //SEGMENT.fade_out(240); // Lower frame rate means less effective fading than FastLED + //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. 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); #ifdef ESP32 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 = random8(); @@ -6476,8 +6479,12 @@ uint16_t mode_midnoise(void) { // Midnoise. By Andrew Tuline. } float volumeSmth = *(float*) um_data->u_data[0]; - SEGMENT.fade_out(SEGMENT.speed); - SEGMENT.fade_out(SEGMENT.speed); + if (SEGENV.call == 0) { + 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. 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]; - 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->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; 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; 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); } - 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 SEGENV.aux0 = secondHand; diff --git a/wled00/FX.h b/wled00/FX.h index 046b7d5b..955203a3 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -571,7 +571,7 @@ typedef struct Segment { 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, 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) void blur(uint8_t); void fill(uint32_t c); @@ -594,14 +594,14 @@ typedef struct Segment { void createjMap(); //WLEDMM jMap void deletejMap(); //WLEDMM jMap #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, 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(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, 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 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); } diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 1fb514ea..a100ecf0 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1132,14 +1132,14 @@ void Segment::fade_out(uint8_t rate) { 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 - uint32_t color = colors[1]; // SEGCOLOR(1); // target color - int w2 = W(color); - int r2 = R(color); - int g2 = G(color); - int b2 = B(color); + uint32_t color2 = colors[1]; // SEGCOLOR(1); // target color // WLEDMM minor optimization + int w2 = W(color2); + int r2 = R(color2); + int g2 = G(color2); + int b2 = B(color2); 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 r1 = R(color); int g1 = G(color); @@ -1156,6 +1156,7 @@ void Segment::fade_out(uint8_t rate) { gdelta += (g2 == g1) ? 0 : (g2 > g1) ? 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); 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_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++) { - if (is2D()) setPixelColorXY((uint16_t)x, (uint16_t)y, CRGB(getPixelColorXY(x,y)).nscale8(scaledown)); - else setPixelColor((uint16_t)x, CRGB(getPixelColor(x)).nscale8(scaledown)); + // WLEDMM minor optimization + if(is2D()) { + 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 part = cur; + CRGB before = cur; // WLEDMM part.nscale8(seep); cur.nscale8(keep); cur += carryover; @@ -1206,7 +1214,8 @@ void Segment::blur(uint8_t blur_amount) 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,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; } } diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index ae853c4d..8f5e1403 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -420,7 +420,9 @@ BusNetwork::BusNetwork(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) { void BusNetwork::setPixelColor(uint16_t pix, uint32_t c) { if (!_valid || pix >= _len) return; if (hasWhite()) c = autoWhiteCalc(c); +#if !defined(WLEDMM_FASTPATH) // WLEDMM expensive operation if (_cct >= 1900) c = colorBalanceFromKelvin(_cct, c); //color correction from CCT +#endif uint16_t offset = pix * _UDPchannels; _data[offset] = R(c); _data[offset+1] = G(c); diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index 136a338e..b39f0d43 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -288,7 +288,7 @@ class BusNetwork : public Bus { 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(); @@ -341,7 +341,7 @@ class BusManager { 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(); diff --git a/wled00/colors.cpp b/wled00/colors.cpp index a35c506e..323edd03 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -11,7 +11,7 @@ IRAM_ATTR_YN uint32_t color_blend(uint32_t color1, uint32_t color2, uint_fast16_ if(blend == 0) return color1; uint_fast16_t blendmax = b16 ? 0xFFFF : 0xFF; 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 r1 = R(color1); diff --git a/wled00/overlay.cpp b/wled00/overlay.cpp index cfee7e81..e7aed986 100644 --- a/wled00/overlay.cpp +++ b/wled00/overlay.cpp @@ -88,7 +88,9 @@ void _overlayAnalogCountdown() } void handleOverlayDraw() { +#if !defined(WLEDMM_FASTPATH) // WLEDMM expensive operation, and most usermods don't draw overlays usermods.handleOverlayDraw(); +#endif if (overlayCurrent == 1) _overlayAnalogClock(); } diff --git a/wled00/pin_manager.cpp b/wled00/pin_manager.cpp index 899a6b7b..6a1880d1 100644 --- a/wled00/pin_manager.cpp +++ b/wled00/pin_manager.cpp @@ -588,7 +588,11 @@ bool PinManagerClass::joinWire(int8_t pinSDA, int8_t pinSCL) { } #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 + #endif #else Wire.begin(pinSDA, pinSCL); // returns void on 8266 #endif diff --git a/wled00/udp.cpp b/wled00/udp.cpp index 7d1d9f82..19ce4e2b 100644 --- a/wled00/udp.cpp +++ b/wled00/udp.cpp @@ -232,11 +232,12 @@ void handleNotifications() if (!udpConnected) return; bool isSupp = false; - size_t packetSize = notifierUdp.parsePacket(); - if (!packetSize && udp2Connected) { + int packetSize = notifierUdp.parsePacket(); // WLEDMM function returns int, not size_t + if ((packetSize < 1) && udp2Connected) { packetSize = notifier2Udp.parsePacket(); isSupp = true; } + if (packetSize < 1) packetSize = 0; // WLEDMM //hyperion / raw RGB if (!packetSize && udpRgbConnected) { diff --git a/wled00/wled.h b/wled00/wled.h index 5d2c15fc..03492ab9 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // 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 //#define WLED_USE_MY_CONFIG diff --git a/wled00/ws.cpp b/wled00/ws.cpp index 07900e77..57983027 100644 --- a/wled00/ws.cpp +++ b/wled00/ws.cpp @@ -185,8 +185,8 @@ static bool sendLiveLedsWs(uint32_t wsClient) // WLEDMM added "static" #ifndef WLED_DISABLE_2D if (strip.isMatrix) { buffer[1] = 2; //version - buffer[2] = Segment::maxWidth; - buffer[3] = Segment::maxHeight; + buffer[2] = min(Segment::maxWidth, (uint16_t) 255); // WLEDMM prevent overflow + buffer[3] = min(Segment::maxHeight, (uint16_t) 255); //WLEDMM: no skipLines } #endif