diff options
author | skcms-skia-autoroll@skia-buildbots.google.com.iam.gserviceaccount.com <skcms-skia-autoroll@skia-buildbots.google.com.iam.gserviceaccount.com> | 2018-04-27 15:35:32 +0000 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-04-27 16:01:12 +0000 |
commit | cbdf5d5bff66b04290409749ff4924bf12b11438 (patch) | |
tree | d98e10116a839bcb5e3101f8127abc13d4fd1be9 /third_party | |
parent | be850adc53e2b2b6397df6b2278802f2354f8204 (diff) |
Roll skia/third_party/skcms 5a327ce..dd901e0 (1 commits)
https://skia.googlesource.com/skcms.git/+log/5a327ce..dd901e0
2018-04-27 mtklein@chromium.org simplify Gauss-Newton interface
The AutoRoll server is located here: https://skcms-skia-roll.skia.org
Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+/master/autoroll/README.md
If the roll is causing failures, please contact the current sheriff, who should
be CC'd on the roll, and stop the roller if necessary.
TBR=stani@google.com
Change-Id: Ie1fd5feba47cddeba47c71dfff2dc4dae1fe12ef
Reviewed-on: https://skia-review.googlesource.com/124285
Reviewed-by: skcms-skia-autoroll <skcms-skia-autoroll@skia-buildbots.google.com.iam.gserviceaccount.com>
Commit-Queue: skcms-skia-autoroll <skcms-skia-autoroll@skia-buildbots.google.com.iam.gserviceaccount.com>
Diffstat (limited to 'third_party')
-rw-r--r-- | third_party/skcms/src/GaussNewton.c | 18 | ||||
-rw-r--r-- | third_party/skcms/src/GaussNewton.h | 22 | ||||
-rw-r--r-- | third_party/skcms/src/PolyTF.c | 39 | ||||
-rw-r--r-- | third_party/skcms/src/TransferFunction.c | 40 | ||||
-rwxr-xr-x | third_party/skcms/version.sha1 | 2 |
5 files changed, 56 insertions, 65 deletions
diff --git a/third_party/skcms/src/GaussNewton.c b/third_party/skcms/src/GaussNewton.c index 5bbc64475d..efbda240a4 100644 --- a/third_party/skcms/src/GaussNewton.c +++ b/third_party/skcms/src/GaussNewton.c @@ -12,18 +12,14 @@ #include <assert.h> #include <string.h> -bool skcms_gauss_newton_step(float (* t)(float x, const void*), - const void* t_ctx, - float (* f)(float x, const void*, const float P[3]), - const void* f_ctx, - void (*grad_f)(float x, const void*, const float P[3], float dfdP[3]), - const void* g_ctx, +bool skcms_gauss_newton_step(float (*rg)(float x, const void*, const float P[3], float dfdP[3]), + const void* ctx, float P[3], float x0, float x1, int N) { // We'll sample x from the range [x0,x1] (both inclusive) N times with even spacing. // // We want to do P' = P + (Jf^T Jf)^-1 Jf^T r(P), - // where r(P) is the residual vector t(x) - f(x,P) + // where r(P) is the residual vector // and Jf is the Jacobian matrix of f(), ∂r/∂P. // // Let's review the shape of each of these expressions: @@ -63,10 +59,8 @@ bool skcms_gauss_newton_step(float (* t)(float x, const void*), for (int i = 0; i < N; i++) { float x = x0 + i*dx; - float resid = t(x,t_ctx) - f(x,f_ctx,P); - float dfdP[3] = {0,0,0}; - grad_f(x,g_ctx,P, dfdP); + float resid = rg(x,ctx,P, dfdP); for (int r = 0; r < 3; r++) { for (int c = 0; c < 3; c++) { @@ -99,9 +93,7 @@ bool skcms_gauss_newton_step(float (* t)(float x, const void*), return true; } -float skcms_eval_curve(float x, const void* vctx) { - const skcms_Curve* curve = (const skcms_Curve*)vctx; - +float skcms_eval_curve(float x, const skcms_Curve* curve) { if (curve->table_entries == 0) { return skcms_TransferFunction_eval(&curve->parametric, x); } diff --git a/third_party/skcms/src/GaussNewton.h b/third_party/skcms/src/GaussNewton.h index 2cabbd0075..2d5174d328 100644 --- a/third_party/skcms/src/GaussNewton.h +++ b/third_party/skcms/src/GaussNewton.h @@ -9,26 +9,20 @@ #include <stdbool.h> -// One Gauss-Newton step, tuning up to 3 parameters P to minimize [ t(x,ctx) - f(x,P) ]^2. +// One Gauss-Newton step, tuning up to 3 parameters P to minimize [ r(x,ctx) ]^2. // -// t: target function of x to approximate -// t_ctx: any context needed for t, passed blindly into calls to t() -// f: function of x,P we're tuning to match t() -// grad_f: gradient of f() at x -// P: in-out, both your initial guess for parameters of f(), and our updated values +// rg: residual function r(x,P) to minimize, and gradient at x in dfdP +// ctx: arbitrary context argument passed to rg +// P: in-out, both your initial guess for parameters of r(), and our updated values // x0,x1,N: N x-values to test in [x0,x1] (both inclusive) with even spacing // // If you have fewer than 3 parameters, set the unused P to zero, don't touch their dfdP. // // Returns true and updates P on success, or returns false on failure. -bool skcms_gauss_newton_step(float (* t)(float x, const void*), - const void* t_ctx, - float (* f)(float x, const void*, const float P[3]), - const void* f_ctx, - void (*grad_f)(float x, const void*, const float P[3], float dfdP[3]), - const void* g_ctx, +bool skcms_gauss_newton_step(float (*rg)(float x, const void*, const float P[3], float dfdP[3]), + const void* ctx, float P[3], float x0, float x1, int N); -// A target function for skcms_Curve, passed as ctx. -float skcms_eval_curve(float x, const void* ctx); +// Evaluate an skcms_Curve at x. +float skcms_eval_curve(float x, const skcms_Curve*); diff --git a/third_party/skcms/src/PolyTF.c b/third_party/skcms/src/PolyTF.c index 0137a3ca8b..b7b34c3d36 100644 --- a/third_party/skcms/src/PolyTF.c +++ b/third_party/skcms/src/PolyTF.c @@ -41,24 +41,30 @@ // It's important to evaluate as f(x) as A(x^3-1) + B(x^2-1) + 1 // and not Ax^3 + Bx^2 + (1-A-B) to ensure that f(1.0f) == 1.0f. -static float eval_poly_tf(float x, const void* ctx, const float P[3]) { - const skcms_PolyTF* tf = (const skcms_PolyTF*)ctx; - - float A = P[0], - C = tf->C, - D = tf->D; - float B = (C*D - A*(D*D*D - 1) - 1) / (D*D - 1); +static float eval_poly_tf(float x, float A, float B, float C, float D) { return x < D ? C*x : A*(x*x*x-1) + B*(x*x-1) + 1; } -static void grad_poly_tf(float x, const void* ctx, const float P[3], float dfdP[3]) { - const skcms_PolyTF* tf = (const skcms_PolyTF*)ctx; - (void)P; - float D = tf->D; +typedef struct { + const skcms_Curve* curve; + const skcms_PolyTF* tf; +} rg_poly_tf_arg; + +static float rg_poly_tf(float x, const void* ctx, const float P[3], float dfdP[3]) { + const rg_poly_tf_arg* arg = (const rg_poly_tf_arg*)ctx; + const skcms_PolyTF* tf = arg->tf; + + float A = P[0], + C = tf->C, + D = tf->D; + float B = (C*D - A*(D*D*D - 1) - 1) / (D*D - 1); dfdP[0] = (x*x*x - 1) - (x*x-1)*(D*D*D-1)/(D*D-1); + + return skcms_eval_curve(x, arg->curve) + - eval_poly_tf(x, A,B,C,D); } static bool fit_poly_tf(const skcms_Curve* curve, skcms_PolyTF* tf) { @@ -116,9 +122,8 @@ static bool fit_poly_tf(const skcms_Curve* curve, skcms_PolyTF* tf) { // Start with guess A = 0, i.e. f(x) ≈ x^2. float P[3] = {0, 0,0}; for (int i = 0; i < 3; i++) { - if (!skcms_gauss_newton_step(skcms_eval_curve, curve, - eval_poly_tf, tf, - grad_poly_tf, tf, + rg_poly_tf_arg arg = { curve, tf }; + if (!skcms_gauss_newton_step(rg_poly_tf, &arg, P, tf->D, 1, N-L)) { return false; @@ -127,13 +132,13 @@ static bool fit_poly_tf(const skcms_Curve* curve, skcms_PolyTF* tf) { float A = tf->A = P[0], C = tf->C, - D = tf->D; - tf->B = (C*D - A*(D*D*D - 1) - 1) / (D*D - 1); + D = tf->D, + B = tf->B = (C*D - A*(D*D*D - 1) - 1) / (D*D - 1); for (int i = 0; i < N; i++) { float x = i * (1.0f/(N-1)); - float rt = skcms_TransferFunction_eval(&inv, eval_poly_tf(x, tf, P)); + float rt = skcms_TransferFunction_eval(&inv, eval_poly_tf(x, A,B,C,D)); if (!isfinitef_(rt)) { return false; } diff --git a/third_party/skcms/src/TransferFunction.c b/third_party/skcms/src/TransferFunction.c index 6daf0cf4d3..b9bbf0b59b 100644 --- a/third_party/skcms/src/TransferFunction.c +++ b/third_party/skcms/src/TransferFunction.c @@ -143,37 +143,38 @@ bool skcms_TransferFunction_invert(const skcms_TransferFunction* src, skcms_Tran // ∂tf/∂b = g(ax + b)^(g-1) // - g(ad + b)^(g-1) -static float eval_nonlinear(float x, const void* ctx, const float P[3]) { - const skcms_TransferFunction* tf = (const skcms_TransferFunction*)ctx; +typedef struct { + const skcms_Curve* curve; + const skcms_TransferFunction* tf; +} rg_nonlinear_arg; - const float g = P[0], a = P[1], b = P[2], - c = tf->c, d = tf->d, f = tf->f; - - const float X = a*x+b, - D = a*d+b; - assert (X >= 0 && D >= 0); +// Return the residual of the skcms_Curve and skcms_TransferFunction with parameters P, +// and fill out the gradient of the residual into dfdP. +static float rg_nonlinear(float x, const void* ctx, const float P[3], float dfdP[3]) { + const rg_nonlinear_arg* arg = (const rg_nonlinear_arg*)ctx; - // (Notice how a large amount of this work is independent of x.) - return powf_(X, g) - - powf_(D, g) - + c*d + f; -} -static void grad_nonlinear(float x, const void* ctx, const float P[3], float dfdP[3]) { - const skcms_TransferFunction* tf = (const skcms_TransferFunction*)ctx; + const skcms_TransferFunction* tf = arg->tf; - const float g = P[0], a = P[1], b = P[2], - d = tf->d; + const float g = P[0], a = P[1], b = P[2], + c = tf->c, d = tf->d, f = tf->f; const float X = a*x+b, D = a*d+b; assert (X >= 0 && D >= 0); + // The gradient. dfdP[0] = 0.69314718f*log2f_(X)*powf_(X, g) - 0.69314718f*log2f_(D)*powf_(D, g); dfdP[1] = x*g*powf_(X, g-1) - d*g*powf_(D, g-1); dfdP[2] = g*powf_(X, g-1) - g*powf_(D, g-1); + + // The residual. + const float t = powf_(X, g) + - powf_(D, g) + + c*d + f; + return skcms_eval_curve(x, arg->curve) - t; } int skcms_fit_linear(const skcms_Curve* curve, int N, float tol, float* c, float* d, float* f) { @@ -232,9 +233,8 @@ static bool fit_nonlinear(const skcms_Curve* curve, int start, int N, skcms_Tran assert (P[1] >= 0 && P[1] * tf->d + P[2] >= 0); - if (!skcms_gauss_newton_step(skcms_eval_curve, curve, - eval_nonlinear, tf, - grad_nonlinear, tf, + rg_nonlinear_arg arg = { curve, tf}; + if (!skcms_gauss_newton_step(rg_nonlinear, &arg, P, start*x_scale, 1, N-start)) { return false; diff --git a/third_party/skcms/version.sha1 b/third_party/skcms/version.sha1 index 7c2fcaddc8..9b9e3a01ba 100755 --- a/third_party/skcms/version.sha1 +++ b/third_party/skcms/version.sha1 @@ -1 +1 @@ -5a327ce9eb094efdb75893d1ac6d46637e006f14
\ No newline at end of file +dd901e0921c663860c813a8bb53b25f8035bccd5
\ No newline at end of file |