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>
This commit is contained in:
parent
be850adc53
commit
cbdf5d5bff
18
third_party/skcms/src/GaussNewton.c
vendored
18
third_party/skcms/src/GaussNewton.c
vendored
@ -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);
|
||||
}
|
||||
|
22
third_party/skcms/src/GaussNewton.h
vendored
22
third_party/skcms/src/GaussNewton.h
vendored
@ -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*);
|
||||
|
39
third_party/skcms/src/PolyTF.c
vendored
39
third_party/skcms/src/PolyTF.c
vendored
@ -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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
40
third_party/skcms/src/TransferFunction.c
vendored
40
third_party/skcms/src/TransferFunction.c
vendored
@ -143,8 +143,17 @@ 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;
|
||||
|
||||
// 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;
|
||||
|
||||
const skcms_TransferFunction* tf = arg->tf;
|
||||
|
||||
const float g = P[0], a = P[1], b = P[2],
|
||||
c = tf->c, d = tf->d, f = tf->f;
|
||||
@ -153,27 +162,19 @@ static float eval_nonlinear(float x, const void* ctx, const float P[3]) {
|
||||
D = a*d+b;
|
||||
assert (X >= 0 && D >= 0);
|
||||
|
||||
// (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 float g = P[0], a = P[1], b = P[2],
|
||||
d = tf->d;
|
||||
|
||||
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;
|
||||
|
2
third_party/skcms/version.sha1
vendored
2
third_party/skcms/version.sha1
vendored
@ -1 +1 @@
|
||||
5a327ce9eb094efdb75893d1ac6d46637e006f14
|
||||
dd901e0921c663860c813a8bb53b25f8035bccd5
|
Loading…
Reference in New Issue
Block a user