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
High Bit Depth Gamma Correction Algorithm for APA102/Dotstar LEDs #1545
Comments
zackees
changed the title
APA102 / Dotstar Gamma Bit shifting gamma correction formula
High Bit Depth Algorithm for APA102/Dotstar LEDs
Sep 28, 2023
Algorithmvoid five_bit_hd_gamma_bitshift(
uint8_t r8, uint8_t g8, uint8_t b8,
uint8_t* out_r8,
uint8_t* out_g8,
uint8_t* out_b8,
uint8_t* out_power_5bit) {
// Step 1: Gamma Correction
uint16_t r16, g16, b16;
five_bit_hd_gamma_function(r8, g8, b8, &r16, &g16, &b16);
// Step 2: Initialize 5-bit brightness.
// Note: we only get 5 levels of brightness
uint8_t v8 = 31;
uint16_t numerator = 1;
uint16_t denominator = 1;
const uint32_t r16_const = r16;
const uint32_t g16_const = g16;
const uint32_t b16_const = b16;
// Step 3: Bit Shifting Loop, can probably replaced with a
// single pass bit-twiddling hack.
do {
// Note that to avoid slow divisions, we multiply the max_value
// by the denominator.
uint32_t max_value = 0xfffful * 15;
if (r16_const * 31 > max_value) {
break;
}
if (g16_const * 31 > max_value) {
break;
}
if (b16_const * 31 > max_value) {
break;
}
numerator = 31;
denominator = 15;
v8 = 15;
max_value = 0xfffful * 15 * 7;
if (r16_const * 31 * 15 > max_value) {
break;
}
if (g16_const * 31 * 15 > max_value) {
break;
}
if (b16_const * 31 * 15 > max_value) {
break;
}
numerator = 31 * 15;
denominator = 15 * 7;
v8 = 7;
max_value = 0xfffful * 15 * 7 * 3;
if (r16_const * 31 * 15 * 7 > max_value) {
break;
}
if (g16_const * 31 * 15 * 7 > max_value) {
break;
}
if (b16_const * 31 * 15 * 7 > max_value) {
break;
}
numerator = 31 * 15 * 7;
denominator = 15 * 7 * 3;
v8 = 3;
max_value = 0xfffful * 15 * 7 * 3;
if (r16_const * 31 * 15 * 7 * 3 > max_value) {
break;
}
if (g16_const * 31 * 15 * 7 * 3 > max_value) {
break;
}
if (b16_const * 31 * 15 * 7 * 3 > max_value) {
break;
}
numerator = 31 * 15 * 7 * 3;
v8 = 1;
} while(false);
r16 = uint16_t(r16_const * numerator / denominator);
g16 = uint16_t(g16_const * numerator / denominator);
b16 = uint16_t(b16_const * numerator / denominator);
// Step 4: Conversion Back to 8-bit.
uint8_t r8_final = (r8 == 255 && uint8_t(r16 >> 8) >= 254) ? 255 : uint8_t(r16 >> 8);
uint8_t g8_final = (g8 == 255 && uint8_t(g16 >> 8) >= 254) ? 255 : uint8_t(g16 >> 8);
uint8_t b8_final = (b8 == 255 && uint8_t(b16 >> 8) >= 254) ? 255 : uint8_t(b16 >> 8);
#if FASTLED_FIVE_BIT_HD_GAMMA_LOW_END_LINEAR_RAMP == 1
if (v8 == 1) {
// Linear tuning for the lowest possible brightness. x=y until
// the intersection point at 9.
if (r8 < 9 && r16 > 0) {
r8_final = r8;
}
if (g8 < 9 && g16 > 0) {
g8_final = g8;
}
if (b8 < 9 && b16 > 0) {
b8_final = b8;
}
}
#endif
// Step 5: Output
*out_r8 = r8_final;
*out_g8 = g8_final;
*out_b8 = b8_final;
*out_power_5bit = v8;
} Output
|
zackees
changed the title
High Bit Depth Algorithm for APA102/Dotstar LEDs
High Bit Depth Gamma Correction Algorithm for APA102/Dotstar LEDs
Sep 28, 2023
@zackees Apologies if I'm out of line, I just ran across this issues during research and noticed it's resolved by the linked (merged) PR. |
Yeah I had to shift scaling post gamma instead of pre gamma. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
High Bit Depth Gamma Correction Algorithm for APA102/Dotstar LEDs
This algorithm gamma corrects into 16 bit then bit shifts against the global brightness then converts back into 8,8,8,5 space.
This gives an additional 5 bits of precision at the low end.
IMG_1274_mute_small.mp4
The text was updated successfully, but these errors were encountered: