diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index e23051a4d..b139bb371 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1230,7 +1230,9 @@ void WS2812FX::show(void) { unsigned long microsStart = micros(); #endif - busses.setBrightness(estimateCurrentAndLimitBri()); + uint8_t newBri = estimateCurrentAndLimitBri(); + if (newBri < _brightness) busses.setBrightness(newBri, true); // "repaint" all pixels + #ifdef WLED_DEBUG sumCurrent += micros() - microsStart; #endif @@ -1240,6 +1242,9 @@ void WS2812FX::show(void) { // See https://github.com/Makuna/NeoPixelBus/wiki/ESP32-NeoMethods#neoesp32rmt-methods busses.show(); + // return bus brightness to original value + if (newBri < _brightness) busses.setBrightness(_brightness); + #ifdef WLED_DEBUG sumMicros += micros() - microsStart; if (++calls == 100) { @@ -1320,11 +1325,16 @@ void WS2812FX::setBrightness(uint8_t b, bool direct) { } } if (direct) { - // would be dangerous if applied immediately (could exceed ABL), but will not output until the next show() - busses.setBrightness(b); + // setting brightness with NeoPixelBusLg has no effect on already painted pixels, + // so we need to force an update to existing buffer + // that would be dangerous if applied immediately (could exceed ABL), but will not output until the next show() + busses.setBrightness(b, true); } else { + // setting brightness with NeoPixelBusLg has no effect on already painted pixels, + // so we need to redraw whole canvas for the change of brightness to take effect + busses.setBrightness(b); unsigned long t = millis(); - if (_segments[0].next_time > t + 22 && t - _lastShow > MIN_SHOW_DELAY) show(); //apply brightness change immediately if no refresh soon + if (_segments[0].next_time > t + 22 && t - _lastShow > MIN_SHOW_DELAY) trigger(); //apply brightness change immediately if no refresh soon } } diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index d798906b8..92aa06fce 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -101,7 +101,9 @@ BusDigital::BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com) : Bus(bc.type, bc.start, bc.autoWhite, bc.count, bc.reversed, (bc.refreshReq || bc.type == TYPE_TM1814)) , _skip(bc.skipAmount) //sacrificial pixels , _colorOrder(bc.colorOrder) +, _prevBri(255) , _colorOrderMap(com) +, _dirty(false) { if (!IS_DIGITAL(bc.type) || !bc.count) return; if (!pinManager.allocatePin(bc.pins[0], true, PinOwner::BusDigital)) return; @@ -118,7 +120,7 @@ BusDigital::BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com) _iType = PolyBus::getI(bc.type, _pins, nr); if (_iType == I_NONE) return; if (bc.doubleBuffer && !allocData(bc.count * (Bus::hasWhite(_type) + 3*Bus::hasRGB(_type)))) return; //warning: hardcoded channel count - buffering = bc.doubleBuffer; + _buffering = bc.doubleBuffer; uint16_t lenToCreate = bc.count; if (bc.type == TYPE_WS2812_1CH_X3) lenToCreate = NUM_ICS_WS2812_1CH_3X(bc.count); // only needs a third of "RGB" LEDs for NeoPixelBus _busPtr = PolyBus::create(_iType, _pins, lenToCreate + _skip, nr, _frequencykHz); @@ -128,8 +130,7 @@ BusDigital::BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com) void BusDigital::show() { if (!_valid) return; - PolyBus::setBrightness(_busPtr, _iType, _bri); - if (buffering) { // should be _data != nullptr, but that causes ~20% FPS drop + if (_buffering) { // should be _data != nullptr, but that causes ~20% FPS drop size_t channels = Bus::hasWhite(_type) + 3*Bus::hasRGB(_type); for (size_t i=0; i<_len; i++) { size_t offset = i*channels; @@ -149,14 +150,9 @@ void BusDigital::show() { else pix += _skip; PolyBus::setPixelColor(_busPtr, _iType, pix, c, co); } - } else { - PolyBus::applyPostAdjustments(_busPtr, _iType); } - PolyBus::show(_busPtr, _iType); - // looks like the following causes periodic miscalculations in ABL when not using double buffering - // when we no longer restore full brightness at busl level we only get a single frame with incorrect brightness - // when turning WLED off otherwise ABL calculations are OK - //PolyBus::setBrightness(_busPtr, _iType, 255); // restore full brightness at bus level (setting unscaled pixel color) + PolyBus::show(_busPtr, _iType, !_buffering); // may be faster if buffer consistency is not important + _dirty = false; } bool BusDigital::canShow() { @@ -164,7 +160,7 @@ bool BusDigital::canShow() { return PolyBus::canShow(_busPtr, _iType); } -void BusDigital::setBrightness(uint8_t b) { +void BusDigital::setBrightness(uint8_t b, bool updateNPBBuffer) { //Fix for turning off onboard LED breaking bus #ifdef LED_BUILTIN if (_bri == 0 && b > 0) { @@ -172,6 +168,12 @@ void BusDigital::setBrightness(uint8_t b) { } #endif Bus::setBrightness(b); + PolyBus::setBrightness(_busPtr, _iType, b); + if (!_buffering && updateNPBBuffer) { + PolyBus::applyPostAdjustments(_busPtr, _iType); + _dirty = true; + _prevBri = b; + } } //If LEDs are skipped, it is possible to use the first as a status LED. @@ -187,7 +189,7 @@ void IRAM_ATTR BusDigital::setPixelColor(uint16_t pix, uint32_t c) { if (!_valid) return; if (Bus::hasWhite(_type)) c = autoWhiteCalc(c); if (_cct >= 1900) c = colorBalanceFromKelvin(_cct, c); //color correction from CCT - if (buffering) { // should be _data != nullptr, but that causes ~20% FPS drop + if (_buffering) { // should be _data != nullptr, but that causes ~20% FPS drop size_t channels = Bus::hasWhite(_type) + 3*Bus::hasRGB(_type); size_t offset = pix*channels; if (Bus::hasRGB(_type)) { @@ -203,7 +205,7 @@ void IRAM_ATTR BusDigital::setPixelColor(uint16_t pix, uint32_t c) { if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs uint16_t pOld = pix; pix = IC_INDEX_WS2812_1CH_3X(pix); - uint32_t cOld = PolyBus::getPixelColor(_busPtr, _iType, pix, co); + uint32_t cOld = restoreColorLossy(PolyBus::getPixelColor(_busPtr, _iType, pix, co)); switch (pOld % 3) { // change only the single channel (TODO: this can cause loss because of get/set) case 0: c = RGBW32(R(cOld), W(c) , B(cOld), 0); break; case 1: c = RGBW32(W(c) , G(cOld), B(cOld), 0); break; @@ -217,7 +219,7 @@ void IRAM_ATTR BusDigital::setPixelColor(uint16_t pix, uint32_t c) { // returns original color if global buffering is enabled, else returns lossly restored color from bus uint32_t BusDigital::getPixelColor(uint16_t pix) { if (!_valid) return 0; - if (buffering) { // should be _data != nullptr, but that causes ~20% FPS drop + if (_buffering) { // should be _data != nullptr, but that causes ~20% FPS drop size_t channels = Bus::hasWhite(_type) + 3*Bus::hasRGB(_type); size_t offset = pix*channels; uint32_t c; @@ -578,9 +580,9 @@ void IRAM_ATTR BusManager::setPixelColor(uint16_t pix, uint32_t c) { } } -void BusManager::setBrightness(uint8_t b) { +void BusManager::setBrightness(uint8_t b, bool updateBuffer) { for (uint8_t i = 0; i < numBusses; i++) { - busses[i]->setBrightness(b); + busses[i]->setBrightness(b, updateBuffer); } } diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index 5b48e7c25..e92d4b6e2 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -124,7 +124,7 @@ class Bus { virtual void setStatusPixel(uint32_t c) {} virtual void setPixelColor(uint16_t pix, uint32_t c) = 0; virtual uint32_t getPixelColor(uint16_t pix) { return 0; } - virtual void setBrightness(uint8_t b) { _bri = b; }; + virtual void setBrightness(uint8_t b, bool updateBuffer = false) { _bri = b; }; virtual void cleanup() = 0; virtual uint8_t getPins(uint8_t* pinArray) { return 0; } virtual uint16_t getLength() { return _len; } @@ -202,7 +202,7 @@ class BusDigital : public Bus { void show(); bool canShow(); - void setBrightness(uint8_t b); + void setBrightness(uint8_t b, bool updateBuffer = false); void setStatusPixel(uint32_t c); void setPixelColor(uint16_t pix, uint32_t c); void setColorOrder(uint8_t colorOrder); @@ -219,17 +219,20 @@ class BusDigital : public Bus { uint8_t _colorOrder; uint8_t _pins[2]; uint8_t _iType; + uint8_t _prevBri; uint16_t _frequencykHz; void * _busPtr; const ColorOrderMap &_colorOrderMap; - bool buffering; // temporary until we figure out why comparison "_data != nullptr" causes severe FPS drop + bool _buffering; // temporary until we figure out why comparison "_data != nullptr" causes severe FPS drop + bool _dirty; inline uint32_t restoreColorLossy(uint32_t c) { - if (_bri < 255) { + uint8_t restoreBri = _dirty ? _prevBri : _bri; + if (restoreBri < 255) { uint8_t* chan = (uint8_t*) &c; for (uint_fast8_t i=0; i<4; i++) { uint_fast16_t val = chan[i]; - chan[i] = ((val << 8) + _bri) / (_bri + 1); //adding _bri slighly improves recovery / stops degradation on re-scale + chan[i] = ((val << 8) + restoreBri) / (restoreBri + 1); //adding _bri slighly improves recovery / stops degradation on re-scale } } return c; @@ -317,7 +320,7 @@ class BusManager { bool canAllShow(); void setStatusPixel(uint32_t c); void setPixelColor(uint16_t pix, uint32_t c); - void setBrightness(uint8_t b); + void setBrightness(uint8_t b, bool updateBuffer = false); void setSegmentCCT(int16_t cct, bool allowWBCorrection = false); uint32_t getPixelColor(uint16_t pix); diff --git a/wled00/bus_wrapper.h b/wled00/bus_wrapper.h index 9807c54bf..8b6ee660f 100644 --- a/wled00/bus_wrapper.h +++ b/wled00/bus_wrapper.h @@ -496,101 +496,101 @@ class PolyBus { return busPtr; } - static void show(void* busPtr, uint8_t busType) { + static void show(void* busPtr, uint8_t busType, bool consistent = true) { switch (busType) { case I_NONE: break; #ifdef ESP8266 - case I_8266_U0_NEO_3: (static_cast(busPtr))->Show(); break; - case I_8266_U1_NEO_3: (static_cast(busPtr))->Show(); break; - case I_8266_DM_NEO_3: (static_cast(busPtr))->Show(); break; - case I_8266_BB_NEO_3: (static_cast(busPtr))->Show(); break; - case I_8266_U0_NEO_4: (static_cast(busPtr))->Show(); break; - case I_8266_U1_NEO_4: (static_cast(busPtr))->Show(); break; - case I_8266_DM_NEO_4: (static_cast(busPtr))->Show(); break; - case I_8266_BB_NEO_4: (static_cast(busPtr))->Show(); break; - case I_8266_U0_400_3: (static_cast(busPtr))->Show(); break; - case I_8266_U1_400_3: (static_cast(busPtr))->Show(); break; - case I_8266_DM_400_3: (static_cast(busPtr))->Show(); break; - case I_8266_BB_400_3: (static_cast(busPtr))->Show(); break; - case I_8266_U0_TM1_4: (static_cast(busPtr))->Show(); break; - case I_8266_U1_TM1_4: (static_cast(busPtr))->Show(); break; - case I_8266_DM_TM1_4: (static_cast(busPtr))->Show(); break; - case I_8266_BB_TM1_4: (static_cast(busPtr))->Show(); break; - case I_8266_U0_TM2_3: (static_cast(busPtr))->Show(); break; - case I_8266_U1_TM2_3: (static_cast(busPtr))->Show(); break; - case I_8266_DM_TM2_3: (static_cast(busPtr))->Show(); break; - case I_8266_BB_TM2_3: (static_cast(busPtr))->Show(); break; - case I_8266_U0_UCS_3: (static_cast(busPtr))->Show(); break; - case I_8266_U1_UCS_3: (static_cast(busPtr))->Show(); break; - case I_8266_DM_UCS_3: (static_cast(busPtr))->Show(); break; - case I_8266_BB_UCS_3: (static_cast(busPtr))->Show(); break; - case I_8266_U0_UCS_4: (static_cast(busPtr))->Show(); break; - case I_8266_U1_UCS_4: (static_cast(busPtr))->Show(); break; - case I_8266_DM_UCS_4: (static_cast(busPtr))->Show(); break; - case I_8266_BB_UCS_4: (static_cast(busPtr))->Show(); break; + case I_8266_U0_NEO_3: (static_cast(busPtr))->Show(consistent); break; + case I_8266_U1_NEO_3: (static_cast(busPtr))->Show(consistent); break; + case I_8266_DM_NEO_3: (static_cast(busPtr))->Show(consistent); break; + case I_8266_BB_NEO_3: (static_cast(busPtr))->Show(consistent); break; + case I_8266_U0_NEO_4: (static_cast(busPtr))->Show(consistent); break; + case I_8266_U1_NEO_4: (static_cast(busPtr))->Show(consistent); break; + case I_8266_DM_NEO_4: (static_cast(busPtr))->Show(consistent); break; + case I_8266_BB_NEO_4: (static_cast(busPtr))->Show(consistent); break; + case I_8266_U0_400_3: (static_cast(busPtr))->Show(consistent); break; + case I_8266_U1_400_3: (static_cast(busPtr))->Show(consistent); break; + case I_8266_DM_400_3: (static_cast(busPtr))->Show(consistent); break; + case I_8266_BB_400_3: (static_cast(busPtr))->Show(consistent); break; + case I_8266_U0_TM1_4: (static_cast(busPtr))->Show(consistent); break; + case I_8266_U1_TM1_4: (static_cast(busPtr))->Show(consistent); break; + case I_8266_DM_TM1_4: (static_cast(busPtr))->Show(consistent); break; + case I_8266_BB_TM1_4: (static_cast(busPtr))->Show(consistent); break; + case I_8266_U0_TM2_3: (static_cast(busPtr))->Show(consistent); break; + case I_8266_U1_TM2_3: (static_cast(busPtr))->Show(consistent); break; + case I_8266_DM_TM2_3: (static_cast(busPtr))->Show(consistent); break; + case I_8266_BB_TM2_3: (static_cast(busPtr))->Show(consistent); break; + case I_8266_U0_UCS_3: (static_cast(busPtr))->Show(consistent); break; + case I_8266_U1_UCS_3: (static_cast(busPtr))->Show(consistent); break; + case I_8266_DM_UCS_3: (static_cast(busPtr))->Show(consistent); break; + case I_8266_BB_UCS_3: (static_cast(busPtr))->Show(consistent); break; + case I_8266_U0_UCS_4: (static_cast(busPtr))->Show(consistent); break; + case I_8266_U1_UCS_4: (static_cast(busPtr))->Show(consistent); break; + case I_8266_DM_UCS_4: (static_cast(busPtr))->Show(consistent); break; + case I_8266_BB_UCS_4: (static_cast(busPtr))->Show(consistent); break; #endif #ifdef ARDUINO_ARCH_ESP32 - case I_32_RN_NEO_3: (static_cast(busPtr))->Show(); break; + case I_32_RN_NEO_3: (static_cast(busPtr))->Show(consistent); break; #ifndef WLED_NO_I2S0_PIXELBUS - case I_32_I0_NEO_3: (static_cast(busPtr))->Show(); break; + case I_32_I0_NEO_3: (static_cast(busPtr))->Show(consistent); break; #endif #ifndef WLED_NO_I2S1_PIXELBUS - case I_32_I1_NEO_3: (static_cast(busPtr))->Show(); break; + case I_32_I1_NEO_3: (static_cast(busPtr))->Show(consistent); break; #endif -// case I_32_BB_NEO_3: (static_cast(busPtr))->Show(); break; - case I_32_RN_NEO_4: (static_cast(busPtr))->Show(); break; +// case I_32_BB_NEO_3: (static_cast(busPtr))->Show(consistent); break; + case I_32_RN_NEO_4: (static_cast(busPtr))->Show(consistent); break; #ifndef WLED_NO_I2S0_PIXELBUS - case I_32_I0_NEO_4: (static_cast(busPtr))->Show(); break; + case I_32_I0_NEO_4: (static_cast(busPtr))->Show(consistent); break; #endif #ifndef WLED_NO_I2S1_PIXELBUS - case I_32_I1_NEO_4: (static_cast(busPtr))->Show(); break; + case I_32_I1_NEO_4: (static_cast(busPtr))->Show(consistent); break; #endif -// case I_32_BB_NEO_4: (static_cast(busPtr))->Show(); break; - case I_32_RN_400_3: (static_cast(busPtr))->Show(); break; +// case I_32_BB_NEO_4: (static_cast(busPtr))->Show(consistent); break; + case I_32_RN_400_3: (static_cast(busPtr))->Show(consistent); break; #ifndef WLED_NO_I2S0_PIXELBUS - case I_32_I0_400_3: (static_cast(busPtr))->Show(); break; + case I_32_I0_400_3: (static_cast(busPtr))->Show(consistent); break; #endif #ifndef WLED_NO_I2S1_PIXELBUS - case I_32_I1_400_3: (static_cast(busPtr))->Show(); break; + case I_32_I1_400_3: (static_cast(busPtr))->Show(consistent); break; #endif -// case I_32_BB_400_3: (static_cast(busPtr))->Show(); break; - case I_32_RN_TM1_4: (static_cast(busPtr))->Show(); break; - case I_32_RN_TM2_3: (static_cast(busPtr))->Show(); break; +// case I_32_BB_400_3: (static_cast(busPtr))->Show(consistent); break; + case I_32_RN_TM1_4: (static_cast(busPtr))->Show(consistent); break; + case I_32_RN_TM2_3: (static_cast(busPtr))->Show(consistent); break; #ifndef WLED_NO_I2S0_PIXELBUS - case I_32_I0_TM1_4: (static_cast(busPtr))->Show(); break; - case I_32_I0_TM2_3: (static_cast(busPtr))->Show(); break; + case I_32_I0_TM1_4: (static_cast(busPtr))->Show(consistent); break; + case I_32_I0_TM2_3: (static_cast(busPtr))->Show(consistent); break; #endif #ifndef WLED_NO_I2S1_PIXELBUS - case I_32_I1_TM1_4: (static_cast(busPtr))->Show(); break; - case I_32_I1_TM2_3: (static_cast(busPtr))->Show(); break; + case I_32_I1_TM1_4: (static_cast(busPtr))->Show(consistent); break; + case I_32_I1_TM2_3: (static_cast(busPtr))->Show(consistent); break; #endif - case I_32_RN_UCS_3: (static_cast(busPtr))->Show(); break; + case I_32_RN_UCS_3: (static_cast(busPtr))->Show(consistent); break; #ifndef WLED_NO_I2S0_PIXELBUS - case I_32_I0_UCS_3: (static_cast(busPtr))->Show(); break; + case I_32_I0_UCS_3: (static_cast(busPtr))->Show(consistent); break; #endif #ifndef WLED_NO_I2S1_PIXELBUS - case I_32_I1_UCS_3: (static_cast(busPtr))->Show(); break; + case I_32_I1_UCS_3: (static_cast(busPtr))->Show(consistent); break; #endif -// case I_32_BB_UCS_3: (static_cast(busPtr))->Show(); break; - case I_32_RN_UCS_4: (static_cast(busPtr))->Show(); break; +// case I_32_BB_UCS_3: (static_cast(busPtr))->Show(consistent); break; + case I_32_RN_UCS_4: (static_cast(busPtr))->Show(consistent); break; #ifndef WLED_NO_I2S0_PIXELBUS - case I_32_I0_UCS_4: (static_cast(busPtr))->Show(); break; + case I_32_I0_UCS_4: (static_cast(busPtr))->Show(consistent); break; #endif #ifndef WLED_NO_I2S1_PIXELBUS - case I_32_I1_UCS_4: (static_cast(busPtr))->Show(); break; + case I_32_I1_UCS_4: (static_cast(busPtr))->Show(consistent); break; #endif -// case I_32_BB_UCS_4: (static_cast(busPtr))->Show(); break; +// case I_32_BB_UCS_4: (static_cast(busPtr))->Show(consistent); break; #endif - case I_HS_DOT_3: (static_cast(busPtr))->Show(); break; - case I_SS_DOT_3: (static_cast(busPtr))->Show(); break; - case I_HS_LPD_3: (static_cast(busPtr))->Show(); break; - case I_SS_LPD_3: (static_cast(busPtr))->Show(); break; - case I_HS_LPO_3: (static_cast(busPtr))->Show(); break; - case I_SS_LPO_3: (static_cast(busPtr))->Show(); break; - case I_HS_WS1_3: (static_cast(busPtr))->Show(); break; - case I_SS_WS1_3: (static_cast(busPtr))->Show(); break; - case I_HS_P98_3: (static_cast(busPtr))->Show(); break; - case I_SS_P98_3: (static_cast(busPtr))->Show(); break; + case I_HS_DOT_3: (static_cast(busPtr))->Show(consistent); break; + case I_SS_DOT_3: (static_cast(busPtr))->Show(consistent); break; + case I_HS_LPD_3: (static_cast(busPtr))->Show(consistent); break; + case I_SS_LPD_3: (static_cast(busPtr))->Show(consistent); break; + case I_HS_LPO_3: (static_cast(busPtr))->Show(consistent); break; + case I_SS_LPO_3: (static_cast(busPtr))->Show(consistent); break; + case I_HS_WS1_3: (static_cast(busPtr))->Show(consistent); break; + case I_SS_WS1_3: (static_cast(busPtr))->Show(consistent); break; + case I_HS_P98_3: (static_cast(busPtr))->Show(consistent); break; + case I_SS_P98_3: (static_cast(busPtr))->Show(consistent); break; } } diff --git a/wled00/wled.h b/wled00/wled.h index 0415a0cc1..e2cbf93d8 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2307130 +#define VERSION 2307180 //uncomment this if you have a "my_config.h" file you'd like to use //#define WLED_USE_MY_CONFIG