From 8fae964ee80df006366fe104b6b4cbbe34b4e5eb Mon Sep 17 00:00:00 2001 From: Christian Schwinne Date: Mon, 20 Sep 2021 21:22:50 +0200 Subject: [PATCH] Allocate segment data based on currently active segments (#2217) --- wled00/FX.cpp | 40 +++++++++++++++++++++++++--------------- wled00/FX.h | 5 +++++ wled00/FX_fcn.cpp | 26 +++++++++++++++----------- 3 files changed, 45 insertions(+), 26 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 718c1f3c6..09cef8328 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -2614,7 +2614,7 @@ uint16_t WS2812FX::mode_glitter() -//each needs 11 bytes +//each needs 12 bytes //Spark type is used for popcorn, 1D fireworks, and drip typedef struct Spark { float pos; @@ -2629,7 +2629,7 @@ typedef struct Spark { */ uint16_t WS2812FX::mode_popcorn(void) { //allocate segment data - uint16_t maxNumPopcorn = 22; // max 22 on 18 segment ESP8266 + uint16_t maxNumPopcorn = 21; // max 21 on 16 segment ESP8266 uint16_t dataSize = sizeof(spark) * maxNumPopcorn; if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed @@ -2688,7 +2688,7 @@ uint16_t WS2812FX::candle(bool multi) if (multi) { //allocate segment data - uint16_t dataSize = (SEGLEN -1) *3; // max length of segment on 18 segment ESP8266 is 75 pixels + uint16_t dataSize = (SEGLEN -1) *3; //max. 1365 pixels (ESP8266) if (!SEGENV.allocateData(dataSize)) return candle(false); //allocation failed } @@ -2776,13 +2776,11 @@ uint16_t WS2812FX::mode_candle_multi() / Speed sets frequency of new starbursts, intensity is the intensity of the burst */ #ifdef ESP8266 - #define STARBURST_MAX_FRAG 4 - #define STARBURST_MAX_STARS 6 + #define STARBURST_MAX_FRAG 8 //52 bytes / star #else - #define STARBURST_MAX_FRAG 10 - #define STARBURST_MAX_STARS 11 + #define STARBURST_MAX_FRAG 10 //60 bytes / star #endif -//each needs 18+STARBURST_MAX_FRAG*4 bytes +//each needs 20+STARBURST_MAX_FRAG*4 bytes typedef struct particle { CRGB color; uint32_t birth =0; @@ -2793,8 +2791,14 @@ typedef struct particle { } star; uint16_t WS2812FX::mode_starburst(void) { + uint16_t maxData = FAIR_DATA_PER_SEG; //ESP8266: 256 ESP32: 640 + uint8_t segs = getActiveSegmentsNum(); + if (segs <= (MAX_NUM_SEGMENTS /2)) maxData *= 2; //ESP8266: 512 if <= 8 segs ESP32: 1280 if <= 16 segs + if (segs <= (MAX_NUM_SEGMENTS /4)) maxData *= 2; //ESP8266: 1024 if <= 4 segs ESP32: 2560 if <= 8 segs + uint16_t maxStars = maxData / sizeof(star); //ESP8266: max. 4/9/19 stars/seg, ESP32: max. 10/21/42 stars/seg + uint8_t numStars = 1 + (SEGLEN >> 3); - if (numStars > STARBURST_MAX_STARS) numStars = STARBURST_MAX_STARS; // 11 * 58 * 32 = 19k (ESP32), 6 * 34 * 18 = 4k (ESP8266) + if (numStars > maxStars) numStars = maxStars; uint16_t dataSize = sizeof(star) * numStars; if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed @@ -2902,18 +2906,24 @@ uint16_t WS2812FX::mode_starburst(void) { * Exploding fireworks effect * adapted from: http://www.anirama.com/1000leds/1d-fireworks/ */ -#ifdef ESP8266 - #define MAX_SPARKS 20 // number of fragments -#else - #define MAX_SPARKS 58 // number of fragments -#endif uint16_t WS2812FX::mode_exploding_fireworks(void) { //allocate segment data - uint16_t numSparks = min(2 + (SEGLEN >> 1), MAX_SPARKS); // max 58 for 32 segment ESP32, 20 for 18 segment ESP8266 + uint16_t maxData = FAIR_DATA_PER_SEG; //ESP8266: 256 ESP32: 640 + uint8_t segs = getActiveSegmentsNum(); + if (segs <= (MAX_NUM_SEGMENTS /2)) maxData *= 2; //ESP8266: 512 if <= 8 segs ESP32: 1280 if <= 16 segs + if (segs <= (MAX_NUM_SEGMENTS /4)) maxData *= 2; //ESP8266: 1024 if <= 4 segs ESP32: 2560 if <= 8 segs + int maxSparks = maxData / sizeof(spark); //ESP8266: max. 21/42/85 sparks/seg, ESP32: max. 53/106/213 sparks/seg + + uint16_t numSparks = min(2 + (SEGLEN >> 1), maxSparks); uint16_t dataSize = sizeof(spark) * numSparks; if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed + if (dataSize != SEGENV.aux1) { //reset to flare if sparks were reallocated + SEGENV.aux0 = 0; + SEGENV.aux1 = dataSize; + } + fill(BLACK); bool actuallyReverse = SEGMENT.getOption(SEG_OPTION_REVERSED); diff --git a/wled00/FX.h b/wled00/FX.h index da2ab8629..ad8b7419e 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -66,6 +66,10 @@ #define MAX_SEGMENT_DATA 20480 #endif +/* How much data bytes each segment should max allocate to leave enough space for other segments, + assuming each segment uses the same amount of data. 256 for ESP8266, 640 for ESP32. */ +#define FAIR_DATA_PER_SEG (MAX_SEGMENT_DATA / MAX_NUM_SEGMENTS) + #define LED_SKIP_AMOUNT 1 #define MIN_SHOW_DELAY 15 @@ -657,6 +661,7 @@ class WS2812FX { getModeCount(void), getPaletteCount(void), getMaxSegments(void), + getActiveSegmentsNum(void), //getFirstSelectedSegment(void), getMainSegmentId(void), gamma8(uint8_t), diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 68595c452..598148fe1 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -129,25 +129,20 @@ void WS2812FX::finalizeInit(uint16_t countPixels) if (autoSegments) { for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) { - _segments[i].start = segStarts[i]; - _segments[i].stop = segStops [i]; + setSegment(i, segStarts[i], segStops[i]); } } else { //expand the main seg to the entire length, but only if there are no other segments uint8_t mainSeg = getMainSegmentId(); - bool isMultipleSegs = false; - for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) - { - if (i != mainSeg && _segments[i].isActive()) isMultipleSegs = true; - } - if (!isMultipleSegs) { - _segments[mainSeg].start = 0; _segments[mainSeg].stop = _length; + + if (getActiveSegmentsNum() < 2) { + setSegment(mainSeg, 0, _length); } else { //there are multiple segments, leave them, but prune length to total for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) { - if (_segments[i].start > _length) _segments[i].stop = 0; - if (_segments[i].stop > _length) _segments[i].stop = _length; + if (_segments[i].start >= _length) setSegment(i, 0, 0); + if (_segments[i].stop > _length) setSegment(i, _segments[i].start, _length); } } } @@ -545,6 +540,15 @@ uint8_t WS2812FX::getMainSegmentId(void) { return 0; } +uint8_t WS2812FX::getActiveSegmentsNum(void) { + uint8_t c = 0; + for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) + { + if (_segments[i].isActive()) c++; + } + return c; +} + uint32_t WS2812FX::getColor(void) { return _segments[getMainSegmentId()].colors[0]; }