aboutsummaryrefslogtreecommitdiffhomepage
path: root/third_party
diff options
context:
space:
mode:
authorGravatar 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
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-04-27 16:01:12 +0000
commitcbdf5d5bff66b04290409749ff4924bf12b11438 (patch)
treed98e10116a839bcb5e3101f8127abc13d4fd1be9 /third_party
parentbe850adc53e2b2b6397df6b2278802f2354f8204 (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.c18
-rw-r--r--third_party/skcms/src/GaussNewton.h22
-rw-r--r--third_party/skcms/src/PolyTF.c39
-rw-r--r--third_party/skcms/src/TransferFunction.c40
-rwxr-xr-xthird_party/skcms/version.sha12
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