another small speedup, and segment stability improvement

* removed a few sanity check that are done again later in getPixelColor
* stability: prevent crashes when changing segments settings or effect options
This commit is contained in:
Frank
2024-08-16 17:54:11 +02:00
parent 1ae8a62cf5
commit 030a7cee53
4 changed files with 48 additions and 12 deletions

View File

@@ -439,6 +439,7 @@ typedef struct Segment {
#ifdef WLEDMM_FASTPATH #ifdef WLEDMM_FASTPATH
// WLEDMM cache some values that won't change while drawing a frame // WLEDMM cache some values that won't change while drawing a frame
bool _isSimpleSegment = false; bool _isSimpleSegment = false;
bool _isSuperSimpleSegment = false;
bool _isValid2D = false; bool _isValid2D = false;
uint8_t _brightness = 255; // final pixel brightness - including transitions and segment opacity uint8_t _brightness = 255; // final pixel brightness - including transitions and segment opacity
bool _firstFill = true; // dirty HACK support bool _firstFill = true; // dirty HACK support

View File

@@ -241,6 +241,7 @@ void Segment::startFrame(void) {
_isValid2D = isActive() && is2D(); _isValid2D = isActive() && is2D();
_brightness = currentBri(on ? opacity : 0); _brightness = currentBri(on ? opacity : 0);
_isSimpleSegment = (grouping == 1) && (spacing == 0); // we can handle pixels faster when no grouping or spacing is involved _isSimpleSegment = (grouping == 1) && (spacing == 0); // we can handle pixels faster when no grouping or spacing is involved
_isSuperSimpleSegment = !mirror && !mirror_y && (grouping == 1) && (spacing == 0); // fastest - we only draw one pixel per call
// if (reverse_y) _isSimpleSegment = false; // for A/B testing // if (reverse_y) _isSimpleSegment = false; // for A/B testing
_2dWidth = is2D() ? calc_virtualWidth() : virtualLength(); _2dWidth = is2D() ? calc_virtualWidth() : virtualLength();
_2dHeight = calc_virtualHeight(); _2dHeight = calc_virtualHeight();
@@ -279,7 +280,8 @@ void IRAM_ATTR __attribute__((hot)) Segment::setPixelColorXY_fast(int x, int y,
// set the requested pixel // set the requested pixel
strip.setPixelColorXY_fast(start + x, startY + y, scaled_col); strip.setPixelColorXY_fast(start + x, startY + y, scaled_col);
bool simpleSegment = !mirror && !mirror_y; //bool simpleSegment = !mirror && !mirror_y;
bool simpleSegment = _isSuperSimpleSegment;
if (simpleSegment) return; // WLEDMM shortcut when no mirroring needed if (simpleSegment) return; // WLEDMM shortcut when no mirroring needed
// handle mirroring // handle mirroring
@@ -306,7 +308,7 @@ void IRAM_ATTR_YN Segment::setPixelColorXY_slow(int x, int y, uint32_t col) //WL
void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) //WLEDMM: IRAM_ATTR conditionally void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) //WLEDMM: IRAM_ATTR conditionally
#endif #endif
{ {
if (Segment::maxHeight==1) return; // not a matrix set-up if ((Segment::maxHeight==1) || !isActive()) return; // not a matrix set-up
const int_fast16_t cols = virtualWidth(); // WLEDMM optimization const int_fast16_t cols = virtualWidth(); // WLEDMM optimization
const int_fast16_t rows = virtualHeight(); const int_fast16_t rows = virtualHeight();
@@ -335,7 +337,8 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) //WLEDMM:
if (transpose) { uint16_t t = x; x = y; y = t; } // swap X & Y if segment transposed if (transpose) { uint16_t t = x; x = y; y = t; } // swap X & Y if segment transposed
// WLEDMM shortcut when no grouping/spacing used // WLEDMM shortcut when no grouping/spacing used
bool simpleSegment = !mirror && !mirror_y && (grouping == 1) && (spacing == 0); //bool simpleSegment = !mirror && !mirror_y && (grouping == 1) && (spacing == 0);
bool simpleSegment = _isSuperSimpleSegment;
if (simpleSegment) { if (simpleSegment) {
strip.setPixelColorXY(start + x, startY + y, col); strip.setPixelColorXY(start + x, startY + y, col);
return; return;
@@ -441,20 +444,21 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColorXY(int x, int y) const {
// Blends the specified color with the existing pixel color. // Blends the specified color with the existing pixel color.
void Segment::blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend) { void Segment::blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend) {
setPixelColorXY(x, y, color_blend(getPixelColorXY(x,y), color, blend)); if (blend == UINT8_MAX) setPixelColorXY(x, y, color);
else setPixelColorXY(x, y, color_blend(getPixelColorXY(x,y), color, blend));
} }
// Adds the specified color with the existing pixel color perserving color balance. // Adds the specified color with the existing pixel color perserving color balance.
void IRAM_ATTR_YN Segment::addPixelColorXY(int x, int y, uint32_t color, bool fast) { void IRAM_ATTR_YN Segment::addPixelColorXY(int x, int y, uint32_t color, bool fast) {
if (!isActive()) return; // not active // if (!isActive()) return; // not active //WLEDMM sanity check is repeated in getPixelColorXY / setPixelColorXY
if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit // if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit //WLEDMM
uint32_t col = getPixelColorXY(x,y); uint32_t col = getPixelColorXY(x,y);
col = color_add(col, color, fast); col = color_add(col, color, fast);
setPixelColorXY(x, y, col); setPixelColorXY(x, y, col);
} }
void Segment::fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { void Segment::fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) {
if (!isActive()) return; // not active // if (!isActive()) return; // not active //WLEDMM sanity check is repeated in getPixelColorXY / setPixelColorXY
CRGB pix = CRGB(getPixelColorXY(x,y)).nscale8_video(fade); CRGB pix = CRGB(getPixelColorXY(x,y)).nscale8_video(fade);
setPixelColorXY(x, y, pix); setPixelColorXY(x, y, pix);
} }

View File

@@ -102,6 +102,12 @@ Segment::Segment(const Segment &orig) {
DEBUG_PRINTLN(F("-- Copy segment constructor --")); DEBUG_PRINTLN(F("-- Copy segment constructor --"));
memcpy((void*)this, (void*)&orig, sizeof(Segment)); //WLEDMM copy to this memcpy((void*)this, (void*)&orig, sizeof(Segment)); //WLEDMM copy to this
transitional = false; // copied segment cannot be in transition transitional = false; // copied segment cannot be in transition
#ifdef WLEDMM_FASTPATH
// WLEDMM temporarily prevent any fast draw calls to the new segment
// _isValid2D = false;
_isSimpleSegment = false;
_isSuperSimpleSegment = false;
#endif
name = nullptr; name = nullptr;
data = nullptr; data = nullptr;
_dataLen = 0; _dataLen = 0;
@@ -143,8 +149,17 @@ void Segment::allocLeds() {
// move constructor --> moves everything (including buffer) from orig to this // move constructor --> moves everything (including buffer) from orig to this
Segment::Segment(Segment &&orig) noexcept { Segment::Segment(Segment &&orig) noexcept {
DEBUG_PRINTLN(F("-- Move segment constructor --")); DEBUG_PRINTLN(F("-- Move segment constructor --"));
#ifdef WLEDMM_FASTPATH
// WLEDMM temporarily prevent any fast draw calls to old and new segment
orig._isSimpleSegment = false;
orig._isSuperSimpleSegment = false;
#endif
memcpy((void*)this, (void*)&orig, sizeof(Segment)); memcpy((void*)this, (void*)&orig, sizeof(Segment));
orig.transitional = false; // old segment cannot be in transition any more orig.transitional = false; // old segment cannot be in transition any more
#ifdef WLEDMM_FASTPATH
// WLEDMM prevent any draw calls to old segment
orig._isValid2D = false;
#endif
orig.name = nullptr; orig.name = nullptr;
orig.data = nullptr; orig.data = nullptr;
orig._dataLen = 0; orig._dataLen = 0;
@@ -169,6 +184,12 @@ Segment& Segment::operator= (const Segment &orig) {
// copy source // copy source
memcpy((void*)this, (void*)&orig, sizeof(Segment)); memcpy((void*)this, (void*)&orig, sizeof(Segment));
transitional = false; transitional = false;
#ifdef WLEDMM_FASTPATH
// WLEDMM prevent any fast draw calls to this segment until the next frame starts
//_isValid2D = false;
_isSimpleSegment = false;
_isSuperSimpleSegment = false;
#endif
// erase pointers to allocated data // erase pointers to allocated data
name = nullptr; name = nullptr;
data = nullptr; data = nullptr;
@@ -196,7 +217,16 @@ Segment& Segment::operator= (Segment &&orig) noexcept {
deallocateData(); // free old runtime data deallocateData(); // free old runtime data
if (_t) { delete _t; _t = nullptr; } if (_t) { delete _t; _t = nullptr; }
if (ledsrgb && !Segment::_globalLeds) free(ledsrgb); //WLEDMM: not needed anymore as we will use leds from copy. no need to nullify ledsrgb as it gets new value in memcpy if (ledsrgb && !Segment::_globalLeds) free(ledsrgb); //WLEDMM: not needed anymore as we will use leds from copy. no need to nullify ledsrgb as it gets new value in memcpy
#ifdef WLEDMM_FASTPATH
// WLEDMM temporarily prevent any fast draw calls to old and new segment
orig._isSimpleSegment = false;
orig._isSuperSimpleSegment = false;
#endif
memcpy((void*)this, (void*)&orig, sizeof(Segment)); memcpy((void*)this, (void*)&orig, sizeof(Segment));
#ifdef WLEDMM_FASTPATH
// WLEDMM temporarily prevent any draw calls to old segment
orig._isValid2D = false;
#endif
orig.name = nullptr; orig.name = nullptr;
orig.data = nullptr; orig.data = nullptr;
orig._dataLen = 0; orig._dataLen = 0;
@@ -956,8 +986,8 @@ void IRAM_ATTR_YN __attribute__((hot)) Segment::setPixelColor(int i, uint32_t co
float rad = 0.0f; float rad = 0.0f;
for (unsigned count = 0; count < numSteps; count++) { for (unsigned count = 0; count < numSteps; count++) {
// may want to try float version as well (with or without antialiasing) // may want to try float version as well (with or without antialiasing)
int x = roundf(sinf(rad) * radius); int x = max(0, min(vW-1, (int)roundf(sinf(rad) * radius)));
int y = roundf(cosf(rad) * radius); int y = max(0, min(vH-1, (int)roundf(cosf(rad) * radius)));
setPixelColorXY(x, y, col); setPixelColorXY(x, y, col);
if(useSymmetry) setPixelColorXY(y, x, col);// WLEDMM if(useSymmetry) setPixelColorXY(y, x, col);// WLEDMM
rad += step; rad += step;
@@ -1388,7 +1418,8 @@ void __attribute__((hot)) Segment::fill(uint32_t c) {
// Blends the specified color with the existing pixel color. // Blends the specified color with the existing pixel color.
void Segment::blendPixelColor(int n, uint32_t color, uint8_t blend) { void Segment::blendPixelColor(int n, uint32_t color, uint8_t blend) {
setPixelColor(n, color_blend(getPixelColor(n), color, blend)); if (blend == UINT8_MAX) setPixelColor(n, color);
else setPixelColor(n, color_blend(getPixelColor(n), color, blend));
} }
// Adds the specified color with the existing pixel color perserving color balance. // Adds the specified color with the existing pixel color perserving color balance.
@@ -1420,7 +1451,7 @@ void Segment::fadePixelColor(uint16_t n, uint8_t fade) {
/* /*
* fade out function, higher rate = quicker fade * fade out function, higher rate = quicker fade
*/ */
void Segment::fade_out(uint8_t rate) { void __attribute__((hot)) Segment::fade_out(uint8_t rate) {
if (!isActive()) return; // not active if (!isActive()) return; // not active
const uint_fast16_t cols = is2D() ? virtualWidth() : virtualLength(); // WLEDMM use fast int types const uint_fast16_t cols = is2D() ? virtualWidth() : virtualLength(); // WLEDMM use fast int types
const uint_fast16_t rows = virtualHeight(); // will be 1 for 1D const uint_fast16_t rows = virtualHeight(); // will be 1 for 1D

View File

@@ -8,7 +8,7 @@
*/ */
// version code in format yymmddb (b = daily build) // version code in format yymmddb (b = daily build)
#define VERSION 2408150 #define VERSION 2408160
// WLEDMM - you can check for this define in usermods, to only enabled WLEDMM specific code in the "right" fork. Its not defined in AC WLED. // WLEDMM - you can check for this define in usermods, to only enabled WLEDMM specific code in the "right" fork. Its not defined in AC WLED.
#define _MoonModules_WLED_ #define _MoonModules_WLED_