From a45306b1411cd746d75e577464538f89e0f605f3 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Thu, 6 Jul 2023 19:51:37 +0200 Subject: [PATCH] blur speedup 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. --- wled00/FX_2Dfcn.cpp | 35 ++++++++++++++++++++--------------- wled00/FX_fcn.cpp | 8 +++++--- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 57f3604e07..11d9ccb1a0 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -324,6 +324,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); @@ -348,50 +349,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 (uint_fast16_t x = 0; x < cols; x++) { //WLEDMM: use fast types + 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 (uint_fast16_t i = 0; i < rows; i++) { //WLEDMM: use fast types - 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; } } @@ -410,8 +415,8 @@ void Segment::box_blur(uint16_t i, bool vertical, fract8 blur_amount) { //WLEDM for (uint_fast16_t j = 0; j < dim1; j++) { uint_fast16_t x = vertical ? i : j; uint_fast16_t y = vertical ? j : i; - uint_fast16_t xp = vertical ? x : x-1; - uint_fast16_t yp = vertical ? y-1 : y; + int_fast16_t xp = vertical ? x : x-1; // "signed" to prevent underflow + int_fast16_t yp = vertical ? y-1 : y; // "signed" to prevent underflow uint_fast16_t xn = vertical ? x : x+1; uint_fast16_t yn = vertical ? y+1 : y; CRGB curr = getPixelColorXY(x,y); diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index fd2b87a992..391e5b8164 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1208,6 +1208,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 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_fast8_t scaledown = 255-fadeBy; // WLEDMM faster to pre-compute this @@ -1229,10 +1230,11 @@ 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 uint_fast16_t cols = virtualWidth(); // WLEDMM use fast int types + 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 @@ -1247,7 +1249,7 @@ void Segment::blur(uint8_t blur_amount) { CRGB cur = CRGB(getPixelColor(i)); CRGB part = cur; - CRGB before = cur; // WLEDMM + uint32_t before = uint32_t(cur); // remember color before blur part.nscale8(seep); cur.nscale8(keep); cur += carryover; @@ -1258,7 +1260,7 @@ void Segment::blur(uint8_t blur_amount) uint8_t b = B(c); setPixelColor((uint16_t)(i-1), qadd8(r, part.red), qadd8(g, part.green), qadd8(b, part.blue)); } - if (before != cur) // WLEDMM optimization: don't write same color again + 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; }