Skip to content

Commit 6332ee6

Browse files
committed
Effect buffer optimisations
setMode() fix for selecting gap UI error messages
1 parent 08d9f7d commit 6332ee6

File tree

8 files changed

+1437
-1442
lines changed

8 files changed

+1437
-1442
lines changed

wled00/FX.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5292,7 +5292,6 @@ uint16_t mode_2Dmatrix(void) { // Matrix2D. By Jeremy Williams.
52925292
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
52935293

52945294
if (SEGENV.call == 0) {
5295-
memset(SEGMENT.data, 0, dataSize); // no falling spawns
52965295
SEGMENT.fill(BLACK);
52975296
SEGENV.step = 0;
52985297
}

wled00/FX.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -543,9 +543,9 @@ typedef struct Segment {
543543

544544
// runtime data functions
545545
inline uint16_t dataSize(void) const { return _dataLen; }
546-
bool allocateData(size_t len);
547-
void deallocateData(void);
548-
void resetIfRequired(void);
546+
bool allocateData(size_t len); // allocates effect data buffer in heap and clears it
547+
void deallocateData(void); // deallocates (frees) effect data buffer from heap
548+
void resetIfRequired(void); // sets all SEGENV variables to 0 and clears data buffer
549549
/**
550550
* Flags that before the next effect is calculated,
551551
* the internal segment state should be reset.
@@ -559,10 +559,10 @@ typedef struct Segment {
559559
void stopTransition(void);
560560
void handleTransition(void);
561561
#ifndef WLED_DISABLE_MODE_BLEND
562-
void swapSegenv(tmpsegd_t &tmpSegD);
563-
void restoreSegenv(tmpsegd_t &tmpSegD);
562+
void swapSegenv(tmpsegd_t &tmpSegD); // copies segment data into specifed buffer, if buffer is not a transition buffer, segment data is overwritten from transition buffer
563+
void restoreSegenv(tmpsegd_t &tmpSegD); // restores segment data from buffer, if buffer is not transition buffer, changed values are copied to transition buffer
564564
#endif
565-
uint16_t progress(void); //transition progression between 0-65535
565+
uint16_t progress(void); // transition progression between 0-65535
566566
uint8_t currentBri(bool useCct = false);
567567
uint8_t currentMode(void);
568568
uint32_t currentColor(uint8_t slot);

wled00/FX_fcn.cpp

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -143,27 +143,28 @@ Segment& Segment::operator= (Segment &&orig) noexcept {
143143
return *this;
144144
}
145145

146+
// allocates effect data buffer on heap and initialises (erases) it
146147
bool IRAM_ATTR Segment::allocateData(size_t len) {
148+
if (len == 0) return false; // nothing to do
147149
if (data && _dataLen >= len) { // already allocated enough (reduce fragmentation)
148150
if (call == 0) memset(data, 0, len); // erase buffer if called during effect initialisation
149151
return true;
150152
}
151153
//DEBUG_PRINTF("-- Allocating data (%d): %p\n", len, this);
152-
deallocateData();
153-
if (len == 0) return false; // nothing to do
154+
deallocateData(); // if the old buffer was smaller release it first
154155
if (Segment::getUsedSegmentData() + len > MAX_SEGMENT_DATA) {
155156
// not enough memory
156157
DEBUG_PRINT(F("!!! Effect RAM depleted: "));
157158
DEBUG_PRINTF("%d/%d !!!\n", len, Segment::getUsedSegmentData());
159+
errorFlag = ERR_NORAM;
158160
return false;
159161
}
160162
// do not use SPI RAM on ESP32 since it is slow
161-
data = (byte*) malloc(len);
163+
data = (byte*)calloc(len, sizeof(byte));
162164
if (!data) { DEBUG_PRINTLN(F("!!! Allocation failed. !!!")); return false; } // allocation failed
163165
Segment::addUsedSegmentData(len);
164166
//DEBUG_PRINTF("--- Allocated data (%p): %d/%d -> %p\n", this, len, Segment::getUsedSegmentData(), data);
165167
_dataLen = len;
166-
memset(data, 0, len);
167168
return true;
168169
}
169170

@@ -194,7 +195,7 @@ void IRAM_ATTR Segment::deallocateData() {
194195
void Segment::resetIfRequired() {
195196
if (!reset) return;
196197
//DEBUG_PRINTF("-- Segment reset: %p\n", this);
197-
deallocateData();
198+
if (data && _dataLen > 0) memset(data, 0, _dataLen); // prevent heap fragmentation (just erase buffer instead of deallocateData())
198199
next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0;
199200
reset = false;
200201
}
@@ -561,35 +562,36 @@ void Segment::setOption(uint8_t n, bool val) {
561562
}
562563

563564
void Segment::setMode(uint8_t fx, bool loadDefaults) {
565+
// skip reserved
566+
while (fx < strip.getModeCount() && strncmp_P("RSVD", strip.getModeData(fx), 4) == 0) fx++;
567+
if (fx >= strip.getModeCount()) fx = 0; // set solid mode
564568
// if we have a valid mode & is not reserved
565-
if (fx < strip.getModeCount() && strncmp_P("RSVD", strip.getModeData(fx), 4)) {
566-
if (fx != mode) {
569+
if (fx != mode) {
567570
#ifndef WLED_DISABLE_MODE_BLEND
568-
if (modeBlending) startTransition(strip.getTransition()); // set effect transitions
571+
if (modeBlending) startTransition(strip.getTransition()); // set effect transitions
569572
#endif
570-
mode = fx;
571-
// load default values from effect string
572-
if (loadDefaults) {
573-
int16_t sOpt;
574-
sOpt = extractModeDefaults(fx, "sx"); speed = (sOpt >= 0) ? sOpt : DEFAULT_SPEED;
575-
sOpt = extractModeDefaults(fx, "ix"); intensity = (sOpt >= 0) ? sOpt : DEFAULT_INTENSITY;
576-
sOpt = extractModeDefaults(fx, "c1"); custom1 = (sOpt >= 0) ? sOpt : DEFAULT_C1;
577-
sOpt = extractModeDefaults(fx, "c2"); custom2 = (sOpt >= 0) ? sOpt : DEFAULT_C2;
578-
sOpt = extractModeDefaults(fx, "c3"); custom3 = (sOpt >= 0) ? sOpt : DEFAULT_C3;
579-
sOpt = extractModeDefaults(fx, "o1"); check1 = (sOpt >= 0) ? (bool)sOpt : false;
580-
sOpt = extractModeDefaults(fx, "o2"); check2 = (sOpt >= 0) ? (bool)sOpt : false;
581-
sOpt = extractModeDefaults(fx, "o3"); check3 = (sOpt >= 0) ? (bool)sOpt : false;
582-
sOpt = extractModeDefaults(fx, "m12"); if (sOpt >= 0) map1D2D = constrain(sOpt, 0, 7); else map1D2D = M12_Pixels; // reset mapping if not defined (2D FX may not work)
583-
sOpt = extractModeDefaults(fx, "si"); if (sOpt >= 0) soundSim = constrain(sOpt, 0, 3);
584-
sOpt = extractModeDefaults(fx, "rev"); if (sOpt >= 0) reverse = (bool)sOpt;
585-
sOpt = extractModeDefaults(fx, "mi"); if (sOpt >= 0) mirror = (bool)sOpt; // NOTE: setting this option is a risky business
586-
sOpt = extractModeDefaults(fx, "rY"); if (sOpt >= 0) reverse_y = (bool)sOpt;
587-
sOpt = extractModeDefaults(fx, "mY"); if (sOpt >= 0) mirror_y = (bool)sOpt; // NOTE: setting this option is a risky business
588-
sOpt = extractModeDefaults(fx, "pal"); if (sOpt >= 0) setPalette(sOpt); //else setPalette(0);
589-
}
590-
markForReset();
591-
stateChanged = true; // send UDP/WS broadcast
573+
mode = fx;
574+
// load default values from effect string
575+
if (loadDefaults) {
576+
int16_t sOpt;
577+
sOpt = extractModeDefaults(fx, "sx"); speed = (sOpt >= 0) ? sOpt : DEFAULT_SPEED;
578+
sOpt = extractModeDefaults(fx, "ix"); intensity = (sOpt >= 0) ? sOpt : DEFAULT_INTENSITY;
579+
sOpt = extractModeDefaults(fx, "c1"); custom1 = (sOpt >= 0) ? sOpt : DEFAULT_C1;
580+
sOpt = extractModeDefaults(fx, "c2"); custom2 = (sOpt >= 0) ? sOpt : DEFAULT_C2;
581+
sOpt = extractModeDefaults(fx, "c3"); custom3 = (sOpt >= 0) ? sOpt : DEFAULT_C3;
582+
sOpt = extractModeDefaults(fx, "o1"); check1 = (sOpt >= 0) ? (bool)sOpt : false;
583+
sOpt = extractModeDefaults(fx, "o2"); check2 = (sOpt >= 0) ? (bool)sOpt : false;
584+
sOpt = extractModeDefaults(fx, "o3"); check3 = (sOpt >= 0) ? (bool)sOpt : false;
585+
sOpt = extractModeDefaults(fx, "m12"); if (sOpt >= 0) map1D2D = constrain(sOpt, 0, 7); else map1D2D = M12_Pixels; // reset mapping if not defined (2D FX may not work)
586+
sOpt = extractModeDefaults(fx, "si"); if (sOpt >= 0) soundSim = constrain(sOpt, 0, 3);
587+
sOpt = extractModeDefaults(fx, "rev"); if (sOpt >= 0) reverse = (bool)sOpt;
588+
sOpt = extractModeDefaults(fx, "mi"); if (sOpt >= 0) mirror = (bool)sOpt; // NOTE: setting this option is a risky business
589+
sOpt = extractModeDefaults(fx, "rY"); if (sOpt >= 0) reverse_y = (bool)sOpt;
590+
sOpt = extractModeDefaults(fx, "mY"); if (sOpt >= 0) mirror_y = (bool)sOpt; // NOTE: setting this option is a risky business
591+
sOpt = extractModeDefaults(fx, "pal"); if (sOpt >= 0) setPalette(sOpt); //else setPalette(0);
592592
}
593+
markForReset();
594+
stateChanged = true; // send UDP/WS broadcast
593595
}
594596
}
595597

wled00/bus_manager.cpp

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -258,23 +258,8 @@ void BusDigital::setBrightness(uint8_t b) {
258258
if (_pins[0] == LED_BUILTIN || _pins[1] == LED_BUILTIN) reinit();
259259
}
260260
#endif
261-
uint8_t prevBri = _bri;
262261
Bus::setBrightness(b);
263262
PolyBus::setBrightness(_busPtr, _iType, b);
264-
/*
265-
if (_data) return; // use _buffering this causes ~20% FPS drop
266-
267-
// must update/repaint every LED in the NeoPixelBus buffer to the new brightness
268-
// the only case where repainting is unnecessary is when all pixels are set after the brightness change but before the next show
269-
// (which we can't rely on)
270-
uint16_t hwLen = _len;
271-
if (_type == TYPE_WS2812_1CH_X3) hwLen = NUM_ICS_WS2812_1CH_3X(_len); // only needs a third of "RGB" LEDs for NeoPixelBus
272-
for (unsigned i = 0; i < hwLen; i++) {
273-
// use 0 as color order, actual order does not matter here as we just update the channel values as-is
274-
uint32_t c = restoreColorLossy(PolyBus::getPixelColor(_busPtr, _iType, i, 0), prevBri);
275-
PolyBus::setPixelColor(_busPtr, _iType, i, c, 0);
276-
}
277-
*/
278263
}
279264

280265
//If LEDs are skipped, it is possible to use the first as a status LED.

wled00/const.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@
345345
#define ERR_CONCURRENCY 2 // Conurrency (client active)
346346
#define ERR_NOBUF 3 // JSON buffer was not released in time, request cannot be handled at this time
347347
#define ERR_NOT_IMPL 4 // Not implemented
348+
#define ERR_NORAM 8 // effect RAM depleted
348349
#define ERR_JSON 9 // JSON parsing failed (input too large?)
349350
#define ERR_FS_BEGIN 10 // Could not init filesystem (no partition?)
350351
#define ERR_FS_QUOTA 11 // The FS is full or the maximum file size is reached

wled00/data/index.js

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,6 @@ function openTab(tabI, force = false)
329329
var timeout;
330330
function showToast(text, error = false)
331331
{
332-
if (error) gId('connind').style.backgroundColor = "var(--c-r)";
333332
var x = gId('toast');
334333
//if (error) text += '<i class="icons btn-icon" style="transform:rotate(45deg);position:absolute;top:10px;right:0px;" onclick="clearErrorToast(100);">&#xe18a;</i>';
335334
x.innerHTML = text;
@@ -342,6 +341,7 @@ function showToast(text, error = false)
342341

343342
function showErrorToast()
344343
{
344+
gId('connind').style.backgroundColor = "var(--c-r)";
345345
showToast('Connection to light failed!', true);
346346
}
347347

@@ -1492,25 +1492,31 @@ function readState(s,command=false)
14921492
gId('checkO3').checked = !(!i.o3);
14931493

14941494
if (s.error && s.error != 0) {
1495-
var errstr = "";
1496-
switch (s.error) {
1497-
case 10:
1498-
errstr = "Could not mount filesystem!";
1499-
break;
1500-
case 11:
1501-
errstr = "Not enough space to save preset!";
1502-
break;
1503-
case 12:
1504-
errstr = "Preset not found.";
1505-
break;
1506-
case 13:
1507-
errstr = "Missing ir.json.";
1508-
break;
1509-
case 19:
1510-
errstr = "A filesystem error has occured.";
1511-
break;
1495+
var errstr = "";
1496+
switch (s.error) {
1497+
case 8:
1498+
errstr = "Effect RAM depleted!";
1499+
break;
1500+
case 9:
1501+
errstr = "JSON parsing error!";
1502+
break;
1503+
case 10:
1504+
errstr = "Could not mount filesystem!";
1505+
break;
1506+
case 11:
1507+
errstr = "Not enough space to save preset!";
1508+
break;
1509+
case 12:
1510+
errstr = "Preset not found.";
1511+
break;
1512+
case 13:
1513+
errstr = "Missing ir.json.";
1514+
break;
1515+
case 19:
1516+
errstr = "A filesystem error has occured.";
1517+
break;
15121518
}
1513-
showToast('Error ' + s.error + ": " + errstr, true);
1519+
showToast('Error ' + s.error + ": " + errstr, true);
15141520
}
15151521

15161522
selectedPal = i.pal;

0 commit comments

Comments
 (0)