@@ -66,13 +66,15 @@ Segment::Segment(const Segment &orig) {
6666 _dataLen = 0 ;
6767 pixels = nullptr ;
6868 if (!stop) return ; // nothing to do if segment is inactive/invalid
69- if (orig.name ) { name = static_cast <char *>(d_malloc (strlen (orig.name )+1 )); if (name) strcpy (name, orig.name ); }
70- if (orig.data ) { if (allocateData (orig._dataLen )) memcpy (data, orig.data , orig._dataLen ); }
7169 if (orig.pixels ) {
70+ // allocate pixel buffer: prefer IRAM/PSRAM
7271 pixels = static_cast <uint32_t *>(d_malloc (sizeof (uint32_t ) * orig.length ()));
73- if (pixels) memcpy (pixels, orig.pixels , sizeof (uint32_t ) * orig.length ());
74- else {
75- DEBUG_PRINTLN (F (" !!! Not enough RAM for pixel buffer !!!" ));
72+ if (pixels) {
73+ memcpy (pixels, orig.pixels , sizeof (uint32_t ) * orig.length ());
74+ if (orig.name ) { name = static_cast <char *>(d_malloc (strlen (orig.name )+1 )); if (name) strcpy (name, orig.name ); }
75+ if (orig.data ) { if (allocateData (orig._dataLen )) memcpy (data, orig.data , orig._dataLen ); }
76+ } else {
77+ DEBUGFX_PRINTLN (F (" !!! Not enough RAM for pixel buffer !!!" ));
7678 errorFlag = ERR_NORAM_PX;
7779 stop = 0 ; // mark segment as inactive/invalid
7880 }
@@ -107,12 +109,14 @@ Segment& Segment::operator= (const Segment &orig) {
107109 pixels = nullptr ;
108110 if (!stop) return *this ; // nothing to do if segment is inactive/invalid
109111 // copy source data
110- if (orig.name ) { name = static_cast <char *>(d_malloc (strlen (orig.name )+1 )); if (name) strcpy (name, orig.name ); }
111- if (orig.data ) { if (allocateData (orig._dataLen )) memcpy (data, orig.data , orig._dataLen ); }
112112 if (orig.pixels ) {
113+ // allocate pixel buffer: prefer IRAM/PSRAM
113114 pixels = static_cast <uint32_t *>(d_malloc (sizeof (uint32_t ) * orig.length ()));
114- if (pixels) memcpy (pixels, orig.pixels , sizeof (uint32_t ) * orig.length ());
115- else {
115+ if (pixels) {
116+ memcpy (pixels, orig.pixels , sizeof (uint32_t ) * orig.length ());
117+ if (orig.name ) { name = static_cast <char *>(d_malloc (strlen (orig.name )+1 )); if (name) strcpy (name, orig.name ); }
118+ if (orig.data ) { if (allocateData (orig._dataLen )) memcpy (data, orig.data , orig._dataLen ); }
119+ } else {
116120 DEBUG_PRINTLN (F (" !!! Not enough RAM for pixel buffer !!!" ));
117121 errorFlag = ERR_NORAM_PX;
118122 stop = 0 ; // mark segment as inactive/invalid
@@ -281,8 +285,9 @@ void Segment::startTransition(uint16_t dur, bool segmentCopy) {
281285 if (_t->_oldSegment ) {
282286 _t->_oldSegment ->palette = _t->_palette ; // restore original palette and colors (from start of transition)
283287 for (unsigned i = 0 ; i < NUM_COLORS; i++) _t->_oldSegment ->colors [i] = _t->_colors [i];
288+ DEBUGFX_PRINTF_P (PSTR (" -- Updated transition with segment copy: S=%p T(%p) O[%p] OP[%p]\n " ), this , _t, _t->_oldSegment , _t->_oldSegment ->pixels );
289+ if (!_t->_oldSegment ->isActive ()) stopTransition ();
284290 }
285- DEBUG_PRINTF_P (PSTR (" -- Updated transition with segment copy: S=%p T(%p) O[%p] OP[%p]\n " ), this , _t, _t->_oldSegment , _t->_oldSegment ->pixels );
286291 }
287292 return ;
288293 }
@@ -298,13 +303,12 @@ void Segment::startTransition(uint16_t dur, bool segmentCopy) {
298303 #endif
299304 for (int i=0 ; i<NUM_COLORS; i++) _t->_colors [i] = colors[i];
300305 if (segmentCopy) _t->_oldSegment = new (std::nothrow) Segment (*this ); // store/copy current segment settings
301- #ifdef WLED_DEBUG
302306 if (_t->_oldSegment ) {
303- DEBUG_PRINTF_P (PSTR (" -- Started transition: S=%p T(%p) O[%p] OP[%p]\n " ), this , _t, _t->_oldSegment , _t->_oldSegment ->pixels );
307+ DEBUGFX_PRINTF_P (PSTR (" -- Started transition: S=%p T(%p) O[%p] OP[%p]\n " ), this , _t, _t->_oldSegment , _t->_oldSegment ->pixels );
308+ if (!_t->_oldSegment ->isActive ()) stopTransition ();
304309 } else {
305- DEBUG_PRINTF_P (PSTR (" -- Started transition without old segment: S=%p T(%p)\n " ), this , _t);
310+ DEBUGFX_PRINTF_P (PSTR (" -- Started transition without old segment: S=%p T(%p)\n " ), this , _t);
306311 }
307- #endif
308312 };
309313}
310314
@@ -425,14 +429,15 @@ void Segment::setGeometry(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, ui
425429
426430 unsigned oldLength = length ();
427431
428- DEBUG_PRINTF_P (PSTR (" Segment geometry: %d,%d -> %d,%d [%d,%d]\n " ), (int )i1, (int )i2, (int )i1Y, (int )i2Y, (int )grp, (int )spc);
432+ DEBUGFX_PRINTF_P (PSTR (" Segment geometry: %d,%d -> %d,%d [%d,%d]\n " ), (int )i1, (int )i2, (int )i1Y, (int )i2Y, (int )grp, (int )spc);
429433 markForReset ();
430- startTransition (strip. getTransition ()) ; // start transition prior to change ( if segment is deactivated (start>stop) no transition will happen)
431- stateChanged = true ; // send UDP/WS broadcast
434+ if (_t) stopTransition () ; // we can't use transition if segment dimensions changed
435+ stateChanged = true ; // send UDP/WS broadcast
432436
433437 // apply change immediately
434438 if (i2 <= i1) { // disable segment
435- d_free (pixels);
439+ deallocateData ();
440+ p_free (pixels);
436441 pixels = nullptr ;
437442 stop = 0 ;
438443 return ;
@@ -449,21 +454,25 @@ void Segment::setGeometry(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, ui
449454 #endif
450455 // safety check
451456 if (start >= stop || startY >= stopY) {
452- d_free (pixels);
457+ deallocateData ();
458+ p_free (pixels);
453459 pixels = nullptr ;
454460 stop = 0 ;
455461 return ;
456462 }
457- // re- allocate FX render buffer
463+ // allocate FX render buffer
458464 if (length () != oldLength) {
459- if (pixels) d_free (pixels); // using realloc on large buffers can cause additional fragmentation instead of reducing it
465+ // allocate render buffer (always entire segment), prefer IRAM/PSRAM. Note: impact on FPS with PSRAM buffer is low (<2% with QSPI PSRAM) on S2/S3
466+ p_free (pixels);
460467 pixels = static_cast <uint32_t *>(d_malloc (sizeof (uint32_t ) * length ()));
461468 if (!pixels) {
462- DEBUG_PRINTLN (F (" !!! Not enough RAM for pixel buffer !!!" ));
469+ DEBUGFX_PRINTLN (F (" !!! Not enough RAM for pixel buffer !!!" ));
470+ deallocateData ();
463471 errorFlag = ERR_NORAM_PX;
464472 stop = 0 ;
465473 return ;
466474 }
475+
467476 }
468477 refreshLightCapabilities ();
469478}
@@ -572,8 +581,8 @@ Segment &Segment::setName(const char *newName) {
572581 if (newLen) {
573582 if (name) d_free (name); // free old name
574583 name = static_cast <char *>(d_malloc (newLen+1 ));
584+ if (mode == FX_MODE_2DSCROLLTEXT) startTransition (strip.getTransition (), true ); // if the name changes in scrolling text mode, we need to copy the segment for blending
575585 if (name) strlcpy (name, newName, newLen+1 );
576- name[newLen] = 0 ;
577586 return *this ;
578587 }
579588 }
@@ -1210,10 +1219,9 @@ void WS2812FX::finalizeInit() {
12101219 deserializeMap (); // (re)load default ledmap (will also setUpMatrix() if ledmap does not exist)
12111220
12121221 // allocate frame buffer after matrix has been set up (gaps!)
1213- if (_pixels) d_free (_pixels); // using realloc on large buffers can cause additional fragmentation instead of reducing it
1222+ d_free (_pixels); // using realloc on large buffers can cause additional fragmentation instead of reducing it
12141223 _pixels = static_cast <uint32_t *>(d_malloc (getLengthTotal () * sizeof (uint32_t )));
12151224 DEBUG_PRINTF_P (PSTR (" strip buffer size: %uB\n " ), getLengthTotal () * sizeof (uint32_t ));
1216-
12171225 DEBUG_PRINTF_P (PSTR (" Heap after strip init: %uB\n " ), ESP.getFreeHeap ());
12181226}
12191227
@@ -1258,7 +1266,8 @@ void WS2812FX::service() {
12581266 // if segment is in transition and no old segment exists we don't need to run the old mode
12591267 // (blendSegments() takes care of On/Off transitions and clipping)
12601268 Segment *segO = seg.getOldSegment ();
1261- if (segO && (seg.mode != segO->mode || blendingStyle != BLEND_STYLE_FADE)) {
1269+ if (segO && segO->isActive () && (seg.mode != segO->mode || blendingStyle != BLEND_STYLE_FADE ||
1270+ (segO->name != seg.name && segO->name && seg.name && strncmp (segO->name , seg.name , WLED_MAX_SEGNAME_LEN) != 0 ))) {
12621271 Segment::modeBlend (true ); // set semaphore for beginDraw() to blend colors and palette
12631272 segO->beginDraw (prog); // set up palette & colors (also sets draw dimensions), parent segment has transition progress
12641273 _currentSegment = segO; // set current segment
@@ -1461,8 +1470,10 @@ void WS2812FX::blendSegment(const Segment &topSegment) const {
14611470 }
14621471 uint32_t c_a = BLACK;
14631472 if (x < vCols && y < vRows) c_a = seg->getPixelColorRaw (x + y*vCols); // will get clipped pixel from old segment or unclipped pixel from new segment
1464- if (segO && blendingStyle == BLEND_STYLE_FADE && topSegment.mode != segO->mode && x < oCols && y < oRows) {
1465- // we need to blend old segment using fade as pixels ae not clipped
1473+ if (segO && blendingStyle == BLEND_STYLE_FADE
1474+ && (topSegment.mode != segO->mode || (segO->name != topSegment.name && segO->name && topSegment.name && strncmp (segO->name , topSegment.name , WLED_MAX_SEGNAME_LEN) != 0 ))
1475+ && x < oCols && y < oRows) {
1476+ // we need to blend old segment using fade as pixels are not clipped
14661477 c_a = color_blend16 (c_a, segO->getPixelColorRaw (x + y*oCols), progInv);
14671478 } else if (blendingStyle != BLEND_STYLE_FADE) {
14681479 // workaround for On/Off transition
@@ -1616,6 +1627,8 @@ static uint8_t estimateCurrentAndLimitBri(uint8_t brightness, uint32_t *pixels)
16161627}
16171628
16181629void WS2812FX::show () {
1630+ if (!_pixels) return ; // no pixels allocated, nothing to show
1631+
16191632 unsigned long showNow = millis ();
16201633 size_t diff = showNow - _lastShow;
16211634
@@ -1888,7 +1901,7 @@ void WS2812FX::makeAutoSegments(bool forceReset) {
18881901 for (size_t i = 1 ; i < s; i++) {
18891902 _segments.emplace_back (segStarts[i], segStops[i]);
18901903 }
1891- DEBUG_PRINTF_P (PSTR (" %d auto segments created.\n " ), _segments.size ());
1904+ DEBUGFX_PRINTF_P (PSTR (" %d auto segments created.\n " ), _segments.size ());
18921905
18931906 } else {
18941907
@@ -2012,7 +2025,7 @@ bool WS2812FX::deserializeMap(unsigned n) {
20122025 }
20132026
20142027 d_free (customMappingTable);
2015- customMappingTable = static_cast <uint16_t *>(d_malloc (sizeof (uint16_t )*getLengthTotal ())); // do not use SPI RAM
2028+ customMappingTable = static_cast <uint16_t *>(d_malloc (sizeof (uint16_t )*getLengthTotal ())); // prefer DRAM for speed
20162029
20172030 if (customMappingTable) {
20182031 DEBUG_PRINTF_P (PSTR (" ledmap allocated: %uB\n " ), sizeof (uint16_t )*getLengthTotal ());
0 commit comments