diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 34fde40058..41106053db 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -150,11 +150,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; @@ -198,7 +196,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 1ba808d8b0..ad9c510be6 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -1003,7 +1003,7 @@ BusHub75Matrix::BusHub75Matrix(const BusConfig &bc) : Bus(bc.type, bc.start, bc. this->_len = (display->width() * display->height()); // note: this returns correct number of pixels but incorrect dimensions if using virtual display (updated below) DEBUGBUS_PRINTF("Length: %u\n", _len); - if (this->_len >= MAX_LEDS) { + if (this->_len > MAX_LEDS) { DEBUGBUS_PRINTLN("MatrixPanel_I2S_DMA Too many LEDS - playing safe"); return; } @@ -1033,7 +1033,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 @@ -1048,9 +1047,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 @@ -1098,11 +1094,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.")); } } @@ -1110,40 +1105,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) { @@ -1153,25 +1135,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() { @@ -1189,7 +1154,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 04ff8ded61..56c240eb3c 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -546,7 +546,7 @@ static_assert(WLED_MAX_BUSSES <= 32, "WLED_MAX_BUSSES exceeds hard limit"); #elif defined(CONFIG_IDF_TARGET_ESP32S2) #define MAX_LEDS 2048 //due to memory constraints S2 #else - #define MAX_LEDS 16384 + #define MAX_LEDS 16384 // note: S3 can take more but 24576 is already unstable using HUB75 (DMA buffers) #endif #endif diff --git a/wled00/util.cpp b/wled00/util.cpp index 20c934b0f1..fa194c9572 100644 --- a/wled00/util.cpp +++ b/wled00/util.cpp @@ -906,8 +906,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 }