Skip to content

Commit

Permalink
blur speedup
Browse files Browse the repository at this point in the history
it seems that SEGMENT.blur() is the main bottleneck for many 2D effects.

This change optimizes performance of the function:
* avoid to re-write unchanged pixels
* early exit when blur_amount == 0 (=nothing to do)
* use _fast_ types where possible

I've seen up to 20% speedup with this change.
  • Loading branch information
softhack007 committed Jul 6, 2023
1 parent fbbf2d5 commit 42b2477
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 22 deletions.
35 changes: 20 additions & 15 deletions wled00/FX_2Dfcn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ void Segment::blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t

// Adds the specified color with the existing pixel color perserving color balance.
void Segment::addPixelColorXY(int x, int y, uint32_t color, bool fast) {
if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit
uint32_t col = getPixelColorXY(x,y);
uint8_t r = R(col);
uint8_t g = G(col);
Expand All @@ -330,50 +331,54 @@ void Segment::fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) {

// blurRow: perform a blur on a row of a rectangular matrix
void Segment::blurRow(uint16_t row, fract8 blur_amount) {
const uint16_t cols = virtualWidth();
const uint16_t rows = virtualHeight();
const uint_fast16_t cols = virtualWidth();
const uint_fast16_t rows = virtualHeight();

if (row >= rows) return;
// blur one row
uint8_t keep = 255 - blur_amount;
uint8_t seep = blur_amount >> 1;
CRGB carryover = CRGB::Black;
for (uint16_t x = 0; x < cols; x++) {
for (uint_fast16_t x = 0; x < cols; x++) {
CRGB cur = getPixelColorXY(x, row);
uint32_t before = uint32_t(cur); // remember color before blur
CRGB part = cur;
part.nscale8(seep);
cur.nscale8(keep);
cur += carryover;
if (x) {
if (x>0) {
CRGB prev = CRGB(getPixelColorXY(x-1, row)) + part;
setPixelColorXY(x-1, row, prev);
}
setPixelColorXY(x, row, cur);
if (before != uint32_t(cur)) // optimization: only set pixel if color has changed
setPixelColorXY(x, row, cur);
carryover = part;
}
}

// blurCol: perform a blur on a column of a rectangular matrix
void Segment::blurCol(uint16_t col, fract8 blur_amount) {
const uint16_t cols = virtualWidth();
const uint16_t rows = virtualHeight();
const uint_fast16_t cols = virtualWidth();
const uint_fast16_t rows = virtualHeight();

if (col >= cols) return;
// blur one column
uint8_t keep = 255 - blur_amount;
uint8_t seep = blur_amount >> 1;
CRGB carryover = CRGB::Black;
for (uint16_t i = 0; i < rows; i++) {
CRGB cur = getPixelColorXY(col, i);
for (uint_fast16_t y = 0; y < rows; y++) {
CRGB cur = getPixelColorXY(col, y);
CRGB part = cur;
uint32_t before = uint32_t(cur); // remember color before blur
part.nscale8(seep);
cur.nscale8(keep);
cur += carryover;
if (i) {
CRGB prev = CRGB(getPixelColorXY(col, i-1)) + part;
setPixelColorXY(col, i-1, prev);
if (y>0) {
CRGB prev = CRGB(getPixelColorXY(col, y-1)) + part;
setPixelColorXY(col, y-1, prev);
}
setPixelColorXY(col, i, cur);
if (before != uint32_t(cur)) // optimization: only set pixel if color has changed
setPixelColorXY(col, y, cur);
carryover = part;
}
}
Expand All @@ -392,8 +397,8 @@ void Segment::box_blur(uint16_t i, bool vertical, fract8 blur_amount) {
for (uint16_t j = 0; j < dim1; j++) {
uint16_t x = vertical ? i : j;
uint16_t y = vertical ? j : i;
uint16_t xp = vertical ? x : x-1;
uint16_t yp = vertical ? y-1 : y;
int16_t xp = vertical ? x : x-1; // "signed" to prevent underflow
int16_t yp = vertical ? y-1 : y; // "signed" to prevent underflow
uint16_t xn = vertical ? x : x+1;
uint16_t yn = vertical ? y+1 : y;
CRGB curr = getPixelColorXY(x,y);
Expand Down
19 changes: 12 additions & 7 deletions wled00/FX_fcn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -887,6 +887,7 @@ void Segment::fade_out(uint8_t rate) {

// fades all pixels to black using nscale8()
void Segment::fadeToBlackBy(uint8_t fadeBy) {
if (fadeBy == 0) return; // optimization - no scaling to apply
const uint16_t cols = is2D() ? virtualWidth() : virtualLength();
const uint16_t rows = virtualHeight(); // will be 1 for 1D

Expand All @@ -901,23 +902,26 @@ void Segment::fadeToBlackBy(uint8_t fadeBy) {
*/
void Segment::blur(uint8_t blur_amount)
{
if (blur_amount == 0) return; // optimization: 0 means "don't blur"
#ifndef WLED_DISABLE_2D
if (is2D()) {
// compatibility with 2D
const uint16_t cols = virtualWidth();
const uint16_t rows = virtualHeight();
for (uint16_t i = 0; i < rows; i++) blurRow(i, blur_amount); // blur all rows
for (uint16_t k = 0; k < cols; k++) blurCol(k, blur_amount); // blur all columns
const uint_fast16_t cols = virtualWidth();
const uint_fast16_t rows = virtualHeight();
for (uint_fast16_t i = 0; i < rows; i++) blurRow(i, blur_amount); // blur all rows
for (uint_fast16_t k = 0; k < cols; k++) blurCol(k, blur_amount); // blur all columns
return;
}
#endif
uint8_t keep = 255 - blur_amount;
uint8_t seep = blur_amount >> 1;
CRGB carryover = CRGB::Black;
for(uint16_t i = 0; i < virtualLength(); i++)
uint_fast16_t vlength = virtualLength();
for(uint_fast16_t i = 0; i < vlength; i++)
{
CRGB cur = CRGB(getPixelColor(i));
CRGB part = cur;
uint32_t before = uint32_t(cur); // remember color before blur
part.nscale8(seep);
cur.nscale8(keep);
cur += carryover;
Expand All @@ -926,9 +930,10 @@ void Segment::blur(uint8_t blur_amount)
uint8_t r = R(c);
uint8_t g = G(c);
uint8_t b = B(c);
setPixelColor(i-1, qadd8(r, part.red), qadd8(g, part.green), qadd8(b, part.blue));
setPixelColor((uint16_t)(i-1), qadd8(r, part.red), qadd8(g, part.green), qadd8(b, part.blue));
}
setPixelColor(i,cur.red, cur.green, cur.blue);
if (before != uint32_t(cur)) // optimization: only set pixel if color has changed
setPixelColor((uint16_t)i,cur.red, cur.green, cur.blue);
carryover = part;
}
}
Expand Down

0 comments on commit 42b2477

Please sign in to comment.