Skip to content

Commit e3653ba

Browse files
authored
Segment fixes (wled#4811)
* Pulling in proper segment memory handling&fixes from @blazoncek dev branch
1 parent 93e011d commit e3653ba

File tree

1 file changed

+43
-30
lines changed

1 file changed

+43
-30
lines changed

wled00/FX_fcn.cpp

Lines changed: 43 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -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

16181629
void 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

Comments
 (0)