Pinwheel speed optimizations

* use "float" math only - sinf(), cosf(), roundf()
* use fewer "rays" for medium-sized matrix (<=32 pixels wide/high)
* ray drawing optimized to use fixed point

up to 80% faster on esp32 and esp32-S3; -S2/-C3 should also see benefits, as these do not have floating point support in hardware.
This commit is contained in:
Frank
2024-02-25 18:00:19 +01:00
parent d9e2fc9a99
commit ff56cf0ee9
2 changed files with 50 additions and 24 deletions

View File

@@ -776,6 +776,16 @@ void Segment::deletejMap() {
}
}
// WLEDMM constants for mapping mode "Pinwheel"
constexpr int Pinwheel_Steps_Medium = 208; // no holes up to 32x32; 60fps
constexpr int Pinwheel_Size_Medium = 32; // larger than this -> use "Big"
constexpr int Pinwheel_Steps_Big = 360; // no holes expected up to 58x58; 40fps
constexpr float Int_to_Rad_Med = (DEG_TO_RAD * 360) / Pinwheel_Steps_Medium; // conversion: from 0...208 to Radians
constexpr float Int_to_Rad_Big = (DEG_TO_RAD * 360) / Pinwheel_Steps_Big; // conversion: from 0...360 to Radians
// WLEDMM end
// 1D strip
uint16_t Segment::virtualLength() const {
#ifndef WLED_DISABLE_2D
@@ -806,7 +816,11 @@ uint16_t Segment::virtualLength() const {
vLen = max(vW,vH) * 0.5; // get the longest dimension
break;
case M12_sPinWheel: //WLEDMM
vLen = 360; // full circle
//vLen = full circle
if (max(vW,vH) <= Pinwheel_Size_Medium)
vLen = Pinwheel_Steps_Medium;
else
vLen = Pinwheel_Steps_Big;
break;
}
return vLen;
@@ -935,24 +949,35 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) //WLEDMM: IRAM_ATT
}
}
break;
case M12_sPinWheel: {
// i = 0 through 359
float centerX = (vW-1) / 2;
float centerY = (vH-1) / 2;
case M12_sPinWheel: { // WLEDMM
// i = angle --> 0 through 359 (Big), OR 0 through 208 (Medium)
float centerX = roundf((vW-1) / 2.0f);
float centerY = roundf((vH-1) / 2.0f);
// int maxDistance = sqrt(centerX * centerX + centerY * centerY) + 1;
int distance = 0;
float cosVal = cosf((float)i * (float)DEG_TO_RAD); // i = current angle
float sinVal = sinf((float)i * (float)DEG_TO_RAD);
while (true) {
int x = roundf(centerX + distance * cosVal);
int y = roundf(centerY + distance * sinVal);
// Check bounds
if (x < 0 || x >= vW || y < 0 || y >= vH) {
break;
}
float angleRad = (max(vW,vH) > Pinwheel_Size_Medium) ? float(i) * Int_to_Rad_Big : float(i) * Int_to_Rad_Med; // angle in radians
float cosVal = cosf(angleRad);
float sinVal = sinf(angleRad);
// draw line at angle, starting at center and ending at the segment edge
// we use fixed point math for better speed. Starting distance is 0.5 for better rounding
constexpr int_fast32_t Fixed_Scale = 512; // fixpoint scaling factor
int_fast32_t posx = (centerX + 0.5f * cosVal) * Fixed_Scale; // X starting position in fixed point
int_fast32_t posy = (centerY + 0.5f * sinVal) * Fixed_Scale; // Y starting position in fixed point
int_fast16_t inc_x = cosVal * Fixed_Scale; // X increment per step (fixed point)
int_fast16_t inc_y = sinVal * Fixed_Scale; // Y increment per step (fixed point)
int32_t maxX = vW * Fixed_Scale; // X edge in fixedpoint
int32_t maxY = vH * Fixed_Scale; // Y edge in fixedpoint
// draw until we hit any edge
while ((posx > 0) && (posy > 0) && (posx < maxX) && (posy < maxY)) {
// scale down to integer (compiler will replace division with appropriate bitshift)
int x = posx / Fixed_Scale;
int y = posy / Fixed_Scale;
// set pixel
setPixelColorXY(x, y, col);
distance++;
// advance to next position
posx += inc_x;
posy += inc_y;
}
break;
}
@@ -1094,12 +1119,13 @@ uint32_t Segment::getPixelColor(int i)
return getPixelColorXY(vW / 2, vH / 2 - i - 1);
break;
case M12_sPinWheel: //WLEDMM
// not 100% accurate, returns outer edge of circle
int distance = min(vH, vW) / 2;
float centerX = (vW - 1) / 2;
float centerY = (vH - 1) / 2;
int x = round(centerX + distance * cos(i * DEG_TO_RAD));
int y = round(centerY + distance * sin(i * DEG_TO_RAD));
// not 100% accurate, returns outer edge of circle
float distance = max(1.0f, min(vH-1, vW-1) / 2.0f);
float centerX = (vW - 1) / 2.0f;
float centerY = (vH - 1) / 2.0f;
float angleRad = (max(vW,vH) > Pinwheel_Size_Medium) ? float(i) * Int_to_Rad_Big : float(i) * Int_to_Rad_Med; // angle in radians
int x = roundf(centerX + distance * cosf(angleRad));
int y = roundf(centerY + distance * sinf(angleRad));
return getPixelColorXY(x, y);
}
return 0;

View File

@@ -8,7 +8,7 @@
*/
// version code in format yymmddb (b = daily build)
#define VERSION 2402250
#define VERSION 2402251
// 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_