diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index cfbc09216e..de244394f3 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -148,11 +148,9 @@ bool Segment::allocateData(size_t len) { if (len == 0) return false; // nothing to do if (data && _dataLen >= len) { // already allocated enough (reduce fragmentation) if (call == 0) { - if (_dataLen < FAIR_DATA_PER_SEG) { // segment data is small //DEBUG_PRINTF_P(PSTR("-- Clearing data (%d): %p\n"), len, this); memset(data, 0, len); // erase buffer if called during effect initialisation return true; // no need to reallocate - } } else return true; @@ -196,7 +194,7 @@ void Segment::deallocateData() { DEBUG_PRINTF_P(PSTR("---- Released data (%p): inconsistent UsedSegmentData (%d/%d), cowardly refusing to free nothing.\n"), this, _dataLen, Segment::getUsedSegmentData()); } data = nullptr; - Segment::addUsedSegmentData(_dataLen <= Segment::getUsedSegmentData() ? -_dataLen : -Segment::getUsedSegmentData()); + Segment::addUsedSegmentData(-_dataLen); // addUsedSegmentData guards agains negative and sets zero if underrun so this is safe _dataLen = 0; } diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 01cfa93a4d..7260d002f7 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -1068,7 +1068,6 @@ BusHub75Matrix::BusHub75Matrix(const BusConfig &bc) : Bus(bc.type, bc.start, bc. display->clearScreen(); // initially clear the screen buffer DEBUGBUS_PRINTLN("MatrixPanel_I2S_DMA clear ok"); - if (_ledBuffer) d_free(_ledBuffer); // should not happen if (_ledsDirty) d_free(_ledsDirty); // should not happen DEBUGBUS_PRINTLN("MatrixPanel_I2S_DMA allocate memory"); _ledsDirty = (byte*) d_malloc(getBitArrayBytes(_len)); // create LEDs dirty bits @@ -1083,9 +1082,6 @@ BusHub75Matrix::BusHub75Matrix(const BusConfig &bc) : Bus(bc.type, bc.start, bc. return; // fail is we cannot get memory for the buffer } setBitArray(_ledsDirty, _len, false); // reset dirty bits - - // create LEDs buffer (initialized to BLACK), prefer DRAM if enough heap is available (faster in case global _pixels buffer is in PSRAM as not both will fit the cache) - _ledBuffer = static_cast(allocate_buffer(_len * sizeof(CRGB), BFRALLOC_PREFER_DRAM | BFRALLOC_CLEAR)); } PANEL_CHAIN_TYPE chainType = CHAIN_NONE; // default for quarter-scan panels that do not use chaining @@ -1133,11 +1129,10 @@ BusHub75Matrix::BusHub75Matrix(const BusConfig &bc) : Bus(bc.type, bc.start, bc. DEBUGBUS_PRINT(F("MatrixPanel_I2S_DMA ")); DEBUGBUS_PRINTF_P(PSTR("%sstarted, width=%u, %u pixels.\n"), _valid? "":"not ", _panelWidth, _len); - if (_ledBuffer != nullptr) DEBUGBUS_PRINTLN(F("MatrixPanel_I2S_DMA LEDS buffer enabled.")); - if (_ledsDirty != nullptr) DEBUGBUS_PRINTLN(F("MatrixPanel_I2S_DMA LEDS dirty bit optimization enabled.")); - if ((_ledBuffer != nullptr) || (_ledsDirty != nullptr)) { - DEBUGBUS_PRINT(F("MatrixPanel_I2S_DMA LEDS buffer uses ")); - DEBUGBUS_PRINT((_ledBuffer? _len*sizeof(CRGB) :0) + (_ledsDirty? getBitArrayBytes(_len) :0)); + if (_ledsDirty != nullptr) { + DEBUGBUS_PRINTLN(F("MatrixPanel_I2S_DMA LEDS dirty bit optimization enabled.")); + DEBUGBUS_PRINT(F("MatrixPanel_I2S_DMA LEDS dirty buffer uses ")); + DEBUGBUS_PRINT((_ledsDirty? getBitArrayBytes(_len) :0)); DEBUGBUS_PRINTLN(F(" bytes.")); } } @@ -1145,40 +1140,27 @@ BusHub75Matrix::BusHub75Matrix(const BusConfig &bc) : Bus(bc.type, bc.start, bc. void IRAM_ATTR BusHub75Matrix::setPixelColor(unsigned pix, uint32_t c) { if (!_valid) return; // note: no need to check pix >= _len as that is checked in containsPixel() // if (_cct >= 1900) c = colorBalanceFromKelvin(_cct, c); //color correction from CCT + if ((c == IS_BLACK) && (getBitFromArray(_ledsDirty, pix) == false)) return; // ignore black if pixel is already black + setBitInArray(_ledsDirty, pix, c != IS_BLACK); // dirty = true means "color is not BLACK" - if (_ledBuffer) { - CRGB fastled_col = CRGB(c); - if (_ledBuffer[pix] != fastled_col) { - _ledBuffer[pix] = fastled_col; - setBitInArray(_ledsDirty, pix, true); // flag pixel as "dirty" - } - } - else { - if ((c == IS_BLACK) && (getBitFromArray(_ledsDirty, pix) == false)) return; // ignore black if pixel is already black - setBitInArray(_ledsDirty, pix, c != IS_BLACK); // dirty = true means "color is not BLACK" + uint8_t r = R(c); + uint8_t g = G(c); + uint8_t b = B(c); - uint8_t r = R(c); - uint8_t g = G(c); - uint8_t b = B(c); - - if (virtualDisp != nullptr) { - int x = pix % _panelWidth; // TODO: check if using & and shift would be faster here, it limits to power-of-2 widths though - int y = pix / _panelWidth; - virtualDisp->drawPixelRGB888(int16_t(x), int16_t(y), r, g, b); - } else { - int x = pix % _panelWidth; - int y = pix / _panelWidth; - display->drawPixelRGB888(int16_t(x), int16_t(y), r, g, b); - } + if (virtualDisp != nullptr) { + int x = pix % _panelWidth; // TODO: check if using & and shift would be faster here, it limits to power-of-2 widths though + int y = pix / _panelWidth; + virtualDisp->drawPixelRGB888(int16_t(x), int16_t(y), r, g, b); + } else { + int x = pix % _panelWidth; + int y = pix / _panelWidth; + display->drawPixelRGB888(int16_t(x), int16_t(y), r, g, b); } } uint32_t BusHub75Matrix::getPixelColor(unsigned pix) const { if (!_valid) return IS_BLACK; // note: no need to check pix >= _len as that is checked in containsPixel() - if (_ledBuffer) - return uint32_t(_ledBuffer[pix]); // fastled-slim already returns RGB, no need to mask out the upper byte - else - return getBitFromArray(_ledsDirty, pix) ? IS_DARKGREY: IS_BLACK; // just a hack - we only know if the pixel is black or not + return getBitFromArray(_ledsDirty, pix) ? IS_DARKGREY: IS_BLACK; // just a hack - we only know if the pixel is black or not } void BusHub75Matrix::setBrightness(uint8_t b) { @@ -1188,25 +1170,8 @@ void BusHub75Matrix::setBrightness(uint8_t b) { } void BusHub75Matrix::show(void) { - if (!_valid) return; - if (_ledBuffer) { - // write out buffered LEDs - unsigned height = _isVirtual ? virtualDisp->height() : display->height(); - unsigned width = _panelWidth; - - //while(!previousBufferFree) delay(1); // experimental - Wait before we allow any writing to the buffer. Stop flicker. - size_t pix = 0; // running pixel index - for (int y=0; ydrawPixelRGB888(int16_t(x), int16_t(y), c.r, c.g, c.b); - else display->drawPixelRGB888(int16_t(x), int16_t(y), c.r, c.g, c.b); - } - pix++; - } - setBitArray(_ledsDirty, _len, false); // buffer shown - reset all dirty bits - } + // show() is a no-op: pixels were already written directly in setPixelColor(), + // the DMA driver handles continuous refresh asynchronously } void BusHub75Matrix::cleanup() { @@ -1224,7 +1189,6 @@ void BusHub75Matrix::cleanup() { #else // runtime reconfiguration is not working on -S3, request reboot from user instead errorFlag = ERR_REBOOT_NEEDED; #endif - if (_ledBuffer != nullptr) d_free(_ledBuffer); _ledBuffer = nullptr; if (_ledsDirty != nullptr) d_free(_ledsDirty); _ledsDirty = nullptr; } diff --git a/wled00/const.h b/wled00/const.h index 38861af7bc..cea011e2cf 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -572,7 +572,7 @@ static_assert(WLED_MAX_BUSSES <= 32, "WLED_MAX_BUSSES exceeds hard limit"); #elif defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32C61) #define MAX_LEDS 4096 #else - #define MAX_LEDS 16384 // classic esp32, S3 and P4 can take more + #define MAX_LEDS 16384 // note: P4/S3 can take more, 24576 is already unstable on S3 using HUB75 (DMA buffers) #endif #endif diff --git a/wled00/util.cpp b/wled00/util.cpp index 5063c1180b..02661200fb 100644 --- a/wled00/util.cpp +++ b/wled00/util.cpp @@ -927,8 +927,8 @@ void *allocate_buffer(size_t size, uint32_t type) { buffer = d_malloc(size); #else if (type & BFRALLOC_PREFER_DRAM) { - if (getContiguousFreeHeap() < 3*(MIN_HEAP_SIZE/2) + size && size > PSRAM_THRESHOLD) - buffer = p_malloc(size); // prefer PSRAM for large allocations & when DRAM is low + if ((getContiguousFreeHeap() < 3*(MIN_HEAP_SIZE/2) + size && size > PSRAM_THRESHOLD) || size > 2*PSRAM_THRESHOLD) + buffer = p_malloc(size); // prefer PSRAM for large allocations & when DRAM is low or when buffer is huge else buffer = d_malloc(size); // allocate in DRAM if enough free heap is available, PSRAM as fallback }