From a1c54bc7f7b2c882139e21dc6bd1c65ba0d66225 Mon Sep 17 00:00:00 2001 From: Ignacio Date: Wed, 10 Oct 2018 14:04:13 -0700 Subject: [PATCH] Add fast sRGB conversion. --- src/nvtt/Surface.cpp | 83 ++++++++++++++++++++++++++++++++++---------- src/nvtt/nvtt.h | 2 ++ 2 files changed, 67 insertions(+), 18 deletions(-) diff --git a/src/nvtt/Surface.cpp b/src/nvtt/Surface.cpp index eac61ba..2d64dea 100644 --- a/src/nvtt/Surface.cpp +++ b/src/nvtt/Surface.cpp @@ -1499,24 +1499,47 @@ static float toSrgb(float f) { return f; } -void Surface::toSrgb() -{ +// sRGB approximation from: http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html +static float toSrgbFast(float f) { + f = saturate(f); + float s1 = sqrtf(f); + float s2 = sqrtf(s1); + float s3 = sqrtf(s2); + return 0.662002687f * s1 + 0.684122060f * s2 - 0.323583601f * s3 - 0.0225411470f * f; +} + +void Surface::toSrgb() { if (isNull()) return; detach(); FloatImage * img = m->image; - const uint count = img->pixelCount(); - for (uint c = 0; c < 3; c++) { - float * channel = img->channel(c); - for (uint i = 0; i < count; i++) { - //parallel_for(count, 128, [=](int i) { - channel[i] = ::toSrgb(channel[i]); - }//); + const uint count = 3 * img->pixelCount(); + float * channel = img->channel(0); + for (uint i = 0; i < count; i++) { + channel[i] = ::toSrgb(channel[i]); + } +} + +void Surface::toSrgbFast() { + if (isNull()) return; + + detach(); + + FloatImage * img = m->image; + + const uint count = 3 * img->pixelCount(); + float * channel = img->channel(0); + for (uint i = 0; i < count; i++) { + channel[i] = ::toSrgbFast(channel[i]); } + //parallel_for(count, 128, [=](int i) { + // channel[i] = toSrgbFast(channel[i]); + //}); } + static float fromSrgb(float f) { if (f < 0.0f) f = 0.0f; else if (f < 0.04045f) f = f / 12.92f; @@ -1525,24 +1548,48 @@ static float fromSrgb(float f) { return f; } -void Surface::toLinearFromSrgb() -{ +// sRGB approximation from: http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html +static float fromSrgbFast(float f) { + f = saturate(f); + return f * (f * (f * 0.305306011f + 0.682171111f) + 0.012522878f); +} + + +void Surface::toLinearFromSrgb() { if (isNull()) return; detach(); FloatImage * img = m->image; - const uint count = img->pixelCount(); - for (uint c = 0; c < 3; c++) { - float * channel = img->channel(c); - for (uint i = 0; i < count; i++) { - //parallel_for(count, 128, [=](int i) { - channel[i] = ::fromSrgb(channel[i]); - }//); + const uint count = 3 *img->pixelCount(); + float * channel = img->channel(0); + for (uint i = 0; i < count; i++) { + channel[i] = ::fromSrgb(channel[i]); } + //parallel_for(count, 128, [=](int i) { + // channel[i] = ::fromSrgb(channel[i]); + //}); } +void Surface::toLinearFromSrgbFast() { + if (isNull()) return; + + detach(); + + FloatImage * img = m->image; + + const uint count = 3 * img->pixelCount(); + float * channel = img->channel(0); + for (uint i = 0; i < count; i++) { + channel[i] = ::fromSrgbFast(channel[i]); + } + //parallel_for(count, 128, [=](int i) { + // channel[i] = ::fromSrgbFast(channel[i]); + //}); +} + + static float toXenonSrgb(float f) { if (f < 0) f = 0; else if (f < (1.0f/16.0f)) f = 4.0f * f; diff --git a/src/nvtt/nvtt.h b/src/nvtt/nvtt.h index d86a503..303a1b4 100644 --- a/src/nvtt/nvtt.h +++ b/src/nvtt/nvtt.h @@ -529,7 +529,9 @@ namespace nvtt NVTT_API void toLinear(int channel, float gamma); NVTT_API void toGamma(int channel, float gamma); NVTT_API void toSrgb(); + NVTT_API void toSrgbFast(); NVTT_API void toLinearFromSrgb(); + NVTT_API void toLinearFromSrgbFast(); NVTT_API void toXenonSrgb(); NVTT_API void transform(const float w0[4], const float w1[4], const float w2[4], const float w3[4], const float offset[4]); NVTT_API void swizzle(int r, int g, int b, int a);