Skip to content

Reduce segment copies #4578

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions wled00/FX.h
Original file line number Diff line number Diff line change
Expand Up @@ -626,7 +626,6 @@ typedef struct Segment {
Segment &setMode(uint8_t fx, bool loadDefaults = false);
Segment &setPalette(uint8_t pal);
Segment &setName(const char* name);
uint8_t differs(const Segment& b) const;
void refreshLightCapabilities();

// runtime data functions
Expand Down Expand Up @@ -883,7 +882,8 @@ class WS2812FX { // 96 bytes
inline void trigger() { _triggered = true; } // Forces the next frame to be computed on all active segments.
inline void setShowCallback(show_callback cb) { _callback = cb; }
inline void setTransition(uint16_t t) { _transitionDur = t; } // sets transition time (in ms)
inline void appendSegment(const Segment &seg = Segment()) { if (_segments.size() < getMaxSegments()) _segments.push_back(seg); }
template<typename... Args>
inline void emplaceSegment(Args&&... args) { if (_segments.size() < getMaxSegments()) _segments.emplace_back(std::forward<Args>(args)...); }
inline void suspend() { _suspend = true; } // will suspend (and canacel) strip.service() execution
inline void resume() { _suspend = false; } // will resume strip.service() execution

Expand Down
42 changes: 9 additions & 33 deletions wled00/FX_fcn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1084,33 +1084,6 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const
return strip.getPixelColor(i);
}

uint8_t Segment::differs(const Segment& b) const {
uint8_t d = 0;
if (start != b.start) d |= SEG_DIFFERS_BOUNDS;
if (stop != b.stop) d |= SEG_DIFFERS_BOUNDS;
if (offset != b.offset) d |= SEG_DIFFERS_GSO;
if (grouping != b.grouping) d |= SEG_DIFFERS_GSO;
if (spacing != b.spacing) d |= SEG_DIFFERS_GSO;
if (opacity != b.opacity) d |= SEG_DIFFERS_BRI;
if (mode != b.mode) d |= SEG_DIFFERS_FX;
if (speed != b.speed) d |= SEG_DIFFERS_FX;
if (intensity != b.intensity) d |= SEG_DIFFERS_FX;
if (palette != b.palette) d |= SEG_DIFFERS_FX;
if (custom1 != b.custom1) d |= SEG_DIFFERS_FX;
if (custom2 != b.custom2) d |= SEG_DIFFERS_FX;
if (custom3 != b.custom3) d |= SEG_DIFFERS_FX;
if (startY != b.startY) d |= SEG_DIFFERS_BOUNDS;
if (stopY != b.stopY) d |= SEG_DIFFERS_BOUNDS;

//bit pattern: (msb first)
// set:2, sound:2, mapping:3, transposed, mirrorY, reverseY, [reset,] paused, mirrored, on, reverse, [selected]
if ((options & 0b1111111111011110U) != (b.options & 0b1111111111011110U)) d |= SEG_DIFFERS_OPT;
if ((options & 0x0001U) != (b.options & 0x0001U)) d |= SEG_DIFFERS_SEL;
for (unsigned i = 0; i < NUM_COLORS; i++) if (colors[i] != b.colors[i]) d |= SEG_DIFFERS_COL;

return d;
}

void Segment::refreshLightCapabilities() {
unsigned capabilities = 0;
unsigned segStartIdx = 0xFFFFU;
Expand Down Expand Up @@ -1786,11 +1759,14 @@ Segment& WS2812FX::getSegment(unsigned id) {
void WS2812FX::resetSegments() {
_segments.clear(); // destructs all Segment as part of clearing
#ifndef WLED_DISABLE_2D
segment seg = isMatrix ? Segment(0, Segment::maxWidth, 0, Segment::maxHeight) : Segment(0, _length);
if (isMatrix) {
_segments.emplace_back(0, Segment::maxWidth, 0, Segment::maxHeight);
} else {
_segments.emplace_back(0, _length);
}
#else
segment seg = Segment(0, _length);
_segments.emplace_back(0, _length);
#endif
_segments.push_back(seg);
_segments.shrink_to_fit(); // just in case ...
_mainSegment = 0;
}
Expand Down Expand Up @@ -1838,12 +1814,12 @@ void WS2812FX::makeAutoSegments(bool forceReset) {
// there is always at least one segment (but we need to differentiate between 1D and 2D)
#ifndef WLED_DISABLE_2D
if (isMatrix)
_segments.push_back(Segment(0, Segment::maxWidth, 0, Segment::maxHeight));
_segments.emplace_back(0, Segment::maxWidth, 0, Segment::maxHeight);
else
#endif
_segments.push_back(Segment(segStarts[0], segStops[0]));
_segments.emplace_back(segStarts[0], segStops[0]);
for (size_t i = 1; i < s; i++) {
_segments.push_back(Segment(segStarts[i], segStops[i]));
_segments.emplace_back(segStarts[i], segStops[i]);
}
DEBUG_PRINTF_P(PSTR("%d auto segments created.\n"), _segments.size());

Expand Down
35 changes: 32 additions & 3 deletions wled00/json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,34 @@
* JSON API (De)serialization
*/

namespace {
bool differs(const Segment& segment, const std::array<byte, sizeof(Segment)>& backup) {
const Segment& segmentBackup = *reinterpret_cast<const Segment*>(backup.data());
if (segment.start != segmentBackup.start) return true;
if (segment.stop != segmentBackup.stop) return true;
if (segment.offset != segmentBackup.offset) return true;
if (segment.grouping != segmentBackup.grouping) return true;
if (segment.spacing != segmentBackup.spacing) return true;
if (segment.opacity != segmentBackup.opacity) return true;
if (segment.mode != segmentBackup.mode) return true;
if (segment.speed != segmentBackup.speed) return true;
if (segment.intensity != segmentBackup.intensity) return true;
if (segment.palette != segmentBackup.palette) return true;
if (segment.custom1 != segmentBackup.custom1) return true;
if (segment.custom2 != segmentBackup.custom2) return true;
if (segment.custom3 != segmentBackup.custom3) return true;
if (segment.startY != segmentBackup.startY) return true;
if (segment.stopY != segmentBackup.stopY) return true;

//bit pattern: (msb first)
// set:2, sound:2, mapping:3, transposed, mirrorY, reverseY, [reset,] paused, mirrored, on, reverse, [selected]
if ((segment.options & 0b1111111111011110U) != (segmentBackup.options & 0b1111111111011110U)) return true;
for (unsigned i = 0; i < NUM_COLORS; i++) if (segment.colors[i] != segmentBackup.colors[i]) return true;

return false;
}
}

bool deserializeSegment(JsonObject elem, byte it, byte presetId)
{
byte id = elem["id"] | it;
Expand All @@ -26,15 +54,16 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
// append segment
if (id >= strip.getSegmentsNum()) {
if (stop <= 0) return false; // ignore empty/inactive segments
strip.appendSegment(Segment(0, strip.getLengthTotal()));
strip.emplaceSegment(0, strip.getLengthTotal());
id = strip.getSegmentsNum()-1; // segments are added at the end of list
newSeg = true;
}

//DEBUG_PRINTLN(F("-- JSON deserialize segment."));
Segment& seg = strip.getSegment(id);
//DEBUG_PRINTF_P(PSTR("-- Original segment: %p (%p)\n"), &seg, seg.data);
const Segment prev = seg; //make a backup so we can tell if something changed (calling copy constructor)
alignas(Segment) std::array<byte, sizeof(Segment)> segmentBackup; //make a backup so we can tell if something changed (voiding copy constructor)
memcpy(segmentBackup.data(), &seg, sizeof(Segment));
//DEBUG_PRINTF_P(PSTR("-- Duplicate segment: %p (%p)\n"), &prev, prev.data);

int start = elem["start"] | seg.start;
Expand Down Expand Up @@ -293,7 +322,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
strip.trigger(); // force segment update
}
// send UDP/WS if segment options changed (except selection; will also deselect current preset)
if (seg.differs(prev) & 0x7F) stateChanged = true;
stateChanged = stateChanged || differs(seg, segmentBackup);

return true;
}
Expand Down
30 changes: 12 additions & 18 deletions wled00/led.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,18 @@ void setValuesFromSegment(uint8_t s)


// applies global legacy values (col, colSec, effectCurrent...)
// problem: if the first selected segment already has the value to be set, other selected segments are not updated
void applyValuesToSelectedSegs()
{
// copy of first selected segment to tell if value was updated
unsigned firstSel = strip.getFirstSelectedSegId();
Segment selsegPrev = strip.getSegment(firstSel);
for (unsigned i = 0; i < strip.getSegmentsNum(); i++) {
Segment& seg = strip.getSegment(i);
if (i != firstSel && (!seg.isActive() || !seg.isSelected())) continue;

if (effectSpeed != selsegPrev.speed) {seg.speed = effectSpeed; stateChanged = true;}
if (effectIntensity != selsegPrev.intensity) {seg.intensity = effectIntensity; stateChanged = true;}
if (effectPalette != selsegPrev.palette) {seg.setPalette(effectPalette);}
if (effectCurrent != selsegPrev.mode) {seg.setMode(effectCurrent);}
uint32_t col0 = RGBW32( col[0], col[1], col[2], col[3]);
uint32_t col1 = RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]);
if (col0 != selsegPrev.colors[0]) {seg.setColor(0, col0);}
if (col1 != selsegPrev.colors[1]) {seg.setColor(1, col1);}
void applyValuesToSelectedSegs() {
const uint32_t col0 = RGBW32( col[0], col[1], col[2], col[3]);
const uint32_t col1 = RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]);
for (Segment& seg : strip._segments) {
if (!(seg.isActive() && seg.isSelected())) continue;
stateChanged = stateChanged || (effectSpeed != seg.speed) || (effectIntensity != seg.intensity);
seg.speed = effectSpeed;
seg.intensity = effectIntensity;
seg.setPalette(effectPalette);
seg.setMode(effectCurrent);
seg.setColor(0, col0);
seg.setColor(1, col1);
}
}

Expand Down
2 changes: 1 addition & 1 deletion wled00/udp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ static void parseNotifyPacket(const uint8_t *udpIn) {
DEBUG_PRINTF_P(PSTR("UDP segment received: %u\n"), id);
if (id > strip.getSegmentsNum()) break;
else if (id == strip.getSegmentsNum()) {
if (receiveSegmentBounds && id < strip.getMaxSegments()) strip.appendSegment();
if (receiveSegmentBounds && id < strip.getMaxSegments()) strip.emplaceSegment();
else break;
}
DEBUG_PRINTF_P(PSTR("UDP segment check: %u\n"), id);
Expand Down