diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 73072e97..d843f4e6 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -114,31 +114,40 @@ void ColorOrderMap::add(uint16_t start, uint16_t len, uint8_t colorOrder) { _count++; } -uint8_t IRAM_ATTR ColorOrderMap::getPixelColorOrder(uint16_t pix, uint8_t defaultColorOrder) const { +uint8_t __attribute__((hot)) ColorOrderMap::getPixelColorOrder(uint16_t pix, uint8_t defaultColorOrder) const { if (_count == 0) return defaultColorOrder; - // upper nibble contains W swap information - uint8_t swapW = defaultColorOrder >> 4; - for (uint8_t i = 0; i < _count; i++) { - if (pix >= _mappings[i].start && pix < (_mappings[i].start + _mappings[i].len)) { - return _mappings[i].colorOrder | (swapW << 4); + // upper nibble contains W swap information // WLEDMM optimization: avoid shifting >>4 and later undo by <<4 + uint8_t swapW = defaultColorOrder & 0xF0; + // Scan mappings, using unsigned range test: pix in [start, start+len) + for (uint_fast8_t i = 0, n = _count; i < n; i++) { // WLEDMM small speedup, by avoiding repeated class member access + const auto &m = _mappings[i]; // WLEDMM help the compiler to optimize + if ((uint16_t)(pix - m.start) < m.len) { // True iff m.len > 0 and pix >= m.start and pix < m.start + m.len + return (m.colorOrder & 0x0F) | swapW; // add W swap information } } return defaultColorOrder; } -uint32_t Bus::autoWhiteCalc(uint32_t c) const { - uint8_t aWM = _autoWhiteMode; - if (_gAWM != AW_GLOBAL_DISABLED) aWM = _gAWM; +uint32_t __attribute__((hot)) Bus::autoWhiteCalc(uint32_t c) const { + uint8_t aWM = (_gAWM != AW_GLOBAL_DISABLED) ? _gAWM : _autoWhiteMode; if (aWM == RGBW_MODE_MANUAL_ONLY) return c; - uint8_t w = W(c); + uint_fast8_t w = W(c); //ignore auto-white calculation if w>0 and mode DUAL (DUAL behaves as BRIGHTER if w==0) if (w > 0 && aWM == RGBW_MODE_DUAL) return c; - uint8_t r = R(c); - uint8_t g = G(c); - uint8_t b = B(c); - if (aWM == RGBW_MODE_MAX) return RGBW32(r, g, b, r > g ? (r > b ? r : b) : (g > b ? g : b)); // brightest RGB channel - w = r < g ? (r < b ? r : b) : (g < b ? g : b); + + uint_fast8_t r = R(c); + uint_fast8_t g = G(c); + uint_fast8_t b = B(c); + // brightest RGB channel + if (aWM == RGBW_MODE_MAX) { // WLEDMM use max() instead of several nested conditions + w = max(r, g); + w = max(w, b); + return RGBW32(r, g, b, w); + } + // Other modes: smallest RGB channel // WLEDMM use min() instead of several nested conditions + w = min(r, g); + w = min(w, b); if (aWM == RGBW_MODE_AUTO_ACCURATE) { r -= w; g -= w; b -= w; } //subtract w in ACCURATE mode return RGBW32(r, g, b, w); } @@ -1231,7 +1240,7 @@ uint32_t BusManager::memUsage(BusConfig &bc) { int BusManager::add(BusConfig &bc) { if (getNumBusses() - getNumVirtualBusses() >= WLED_MAX_BUSSES) return -1; // WLEDMM clear cached Bus info first - lastend = 0; + lastlen = 0; laststart = 0; lastBus = nullptr; slowMode = false; @@ -1272,7 +1281,7 @@ void BusManager::removeAll() { // WLEDMM clear cached Bus info lastBus = nullptr; laststart = 0; - lastend = 0; + lastlen = 0; slowMode = false; } @@ -1293,24 +1302,28 @@ void BusManager::setStatusPixel(uint32_t c) { } } -void IRAM_ATTR __attribute__((hot)) BusManager::setPixelColor(uint16_t pix, uint32_t c, int16_t cct) { - if (!slowMode && (pix >= laststart) && (pix < lastend ) && lastBus->isOk()) { - // WLEDMM same bus as last time - no need to search again +void IRAM_ATTR __attribute__((hot)) BusManager::setPixelColor(uint16_t pix, uint32_t c) { + // Fast path: check cached bus first (with proper nullptr check) + // optimization: below is True iff lastlen > 0 and pix >= laststart and pix < laststart + lastlen + if (!slowMode && lastBus && ((uint_fast16_t)(pix - laststart) < lastlen) && lastBus->isOk()) { // WLEDMM saves us a few cycles for each pixel lastBus->setPixelColor(pix - laststart, c); return; } - for (uint_fast8_t i = 0; i < numBusses; i++) { // WLEDMM use fast native types - Bus* b = busses[i]; - if (b->isOk() == false) continue; // WLEDMM ignore invalid (=not ready) busses + // Slow path: search through all buses + uint_fast8_t count = numBusses; // Cache to avoid repeated member access + for (uint_fast8_t i = 0; i < count; i++) { + Bus* const b = busses[i]; // Use const pointer for optimization hint + if ((!b) || (b->isOk() == false)) continue; // WLEDMM ignore invalid (=not ready) busses uint_fast16_t bstart = b->getStart(); - if (pix < bstart || pix >= bstart + b->getLength()) continue; - else { + uint_fast16_t blen = b->getLength(); + + if ((uint_fast16_t)(pix - bstart) < blen) { // Unsigned arithmetic trick for fast range check if (!slowMode) { - // WLEDMM remember last Bus we took + // Cache bus info for next call lastBus = b; laststart = bstart; - lastend = bstart + b->getLength(); + lastlen = blen; } b->setPixelColor(pix - bstart, c); if (!slowMode) break; // WLEDMM found the right Bus -> so we can stop searching - unless we have busses that overlap @@ -1334,46 +1347,52 @@ void __attribute__((cold)) BusManager::setSegmentCCT(int16_t cct, bool allowWBCo } uint32_t IRAM_ATTR __attribute__((hot)) BusManager::getPixelColor(uint_fast16_t pix) { // WLEDMM use fast native types, IRAM_ATTR - if ((pix >= laststart) && (pix < lastend ) && (lastBus != nullptr) && lastBus->isOk()) { + // Fast path: check cached bus first (with proper null check, and unsigned arithmetic trick for faster range check) + if (lastBus && ((uint_fast16_t)(pix - laststart) < lastlen) && lastBus->isOk()) { // WLEDMM same bus as last time - no need to search again return lastBus->getPixelColor(pix - laststart); } - for (uint_fast8_t i = 0; i < numBusses; i++) { - Bus* b = busses[i]; - if (b->isOk() == false) continue; // WLEDMM ignore invalid (=not ready) busses + uint_fast8_t count = numBusses; // Cache to avoid repeated member access + for (uint_fast8_t i = 0; i < count; i++) { + Bus* const b = busses[i]; // Use const pointer for optimization hint + if ((!b) || (b->isOk() == false)) continue; // WLEDMM ignore invalid (=not ready) busses uint_fast16_t bstart = b->getStart(); - if (pix < bstart || pix >= bstart + b->getLength()) continue; - else { + uint_fast16_t blen = b->getLength(); + + if ((uint_fast16_t)(pix - bstart) < blen) { // Unsigned arithmetic trick for fast range check if (!slowMode) { - // WLEDMM remember last Bus we took + // Cache bus info for next call lastBus = b; laststart = bstart; - lastend = bstart + b->getLength(); + lastlen = blen; } - return b->getPixelColor(pix - bstart); + return b->getPixelColor(pix - bstart); // done - found one } } return 0; } uint32_t IRAM_ATTR __attribute__((hot)) BusManager::getPixelColorRestored(uint_fast16_t pix) { // WLEDMM uses bus::getPixelColorRestored() - if ((pix >= laststart) && (pix < lastend ) && (lastBus != nullptr) && lastBus->isOk()) { + // Fast path: check cached bus first (with proper null check, and unsigned arithmetic trick for faster range check) + if (lastBus && ((uint_fast16_t)(pix - laststart) < lastlen) && lastBus->isOk()) { // WLEDMM same bus as last time - no need to search again return lastBus->getPixelColorRestored(pix - laststart); } - for (uint_fast8_t i = 0; i < numBusses; i++) { - Bus* b = busses[i]; - if (b->isOk() == false) continue; // WLEDMM ignore invalid (=not ready) busses + uint_fast8_t count = numBusses; // Cache to avoid repeated member access + for (uint_fast8_t i = 0; i < count; i++) { + Bus* const b = busses[i]; // Use const pointer for optimization hint + if ((!b) || (b->isOk() == false)) continue; // WLEDMM ignore invalid (=not ready) busses uint_fast16_t bstart = b->getStart(); - if (pix < bstart || pix >= bstart + b->getLength()) continue; - else { + uint_fast16_t blen = b->getLength(); + + if ((uint_fast16_t)(pix - bstart) < blen) { // Unsigned arithmetic trick for range check if (!slowMode) { - // WLEDMM remember last Bus we took + // Cache bus info for next call lastBus = b; laststart = bstart; - lastend = bstart + b->getLength(); + lastlen = blen; } return b->getPixelColorRestored(pix - bstart); } diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index e49238d6..ea886eaf 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -463,13 +463,14 @@ class BusManager { // WLEDMM clear cached Bus info lastBus = nullptr; laststart = 0; - lastend = 0; + lastlen= 0; slowMode = isRTMode; } void setStatusPixel(uint32_t c); - void setPixelColor(uint16_t pix, uint32_t c, int16_t cct=-1); + void setPixelColor(uint16_t pix, uint32_t c); // WLEDMM third parameter "cct" is never used - removed + //void setPixelColor(uint16_t pix, uint32_t c, int16_t cct) {Bus::setCCT(cct); setPixelColor(pix, c);}; // WLEDMM legacy support - slow, avoid using it void setBrightness(uint8_t b, bool immediate=false); // immediate=true is for use in ABL, it applies brightness immediately (warning: inefficient) @@ -504,7 +505,7 @@ class BusManager { // WLEDMM cache last used Bus -> 20% to 30% speedup when using many LED pins Bus *lastBus = nullptr; unsigned laststart = 0; - unsigned lastend = 0; + unsigned lastlen = 0; bool slowMode = false; // WLEDMM not sure why we need this. But its necessary. inline uint8_t getNumVirtualBusses() const {