Roll skia/third_party/skcms 5c593bf702db..a52db47aa53f (1 commits)
https://skia.googlesource.com/skcms.git/+log/5c593bf702db..a52db47aa53f git log 5c593bf702db..a52db47aa53f --date=short --no-merges --format='%ad %ae %s' 2019-10-08 mtklein@google.com sketch PQ and HLG APIs Created with: gclient setdep -r skia/third_party/skcms@a52db47aa53f If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/skcms-skia-autoroll Please CC kjlubick@google.com,mtklein@google.com on the revert to ensure that a human is aware of the problem. To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+/master/autoroll/README.md CQ_INCLUDE_TRYBOTS=luci.chromium.try:linux-blink-rel Bug: None Change-Id: I9f9eeabe7760c31b73a2ed4d64bce1027fd2a9f7 TBR=kjlubick@google.com,mtklein@google.com TBR=kjlubick@google.com,mtklein@google.com Reviewed-on: https://skia-review.googlesource.com/c/skia/+/247074 Reviewed-by: skia-autoroll <skia-autoroll@skia-public.iam.gserviceaccount.com> Commit-Queue: skia-autoroll <skia-autoroll@skia-public.iam.gserviceaccount.com>
This commit is contained in:
parent
8803c2d8f3
commit
c093cc838f
44
include/third_party/skcms/skcms.h
vendored
44
include/third_party/skcms/skcms.h
vendored
@ -51,6 +51,50 @@ SKCMS_API float skcms_TransferFunction_eval (const skcms_TransferFunction*, flo
|
||||
SKCMS_API bool skcms_TransferFunction_invert(const skcms_TransferFunction*,
|
||||
skcms_TransferFunction*);
|
||||
|
||||
// We can jam a couple alternate transfer function forms into skcms_TransferFunction,
|
||||
// including those matching the general form of the SMPTE ST 2084 PQ function and its inverse:
|
||||
//
|
||||
// max(A + B|x|^C, 0)
|
||||
// tf(x) = sign(x) * (------------------) ^ F
|
||||
// (D + E|x|^C)
|
||||
SKCMS_API bool skcms_TransferFunction_makePQish(skcms_TransferFunction*,
|
||||
float A, float B, float C,
|
||||
float D, float E, float F);
|
||||
|
||||
static inline bool skcms_TransferFunction_makePQ(skcms_TransferFunction* tf) {
|
||||
return skcms_TransferFunction_makePQish(tf, -107/128.0f, 1.0f, 32/2523.0f
|
||||
, 2413/128.0f, -2392/128.0f, 8192/1305.0f);
|
||||
}
|
||||
static inline bool skcms_TransferFunction_makePQinv(skcms_TransferFunction* tf) {
|
||||
return skcms_TransferFunction_makePQish(tf, 107/128.0f, 2413/128.0f, 1305/8192.0f
|
||||
, 1.0f, 2392/128.0f, 2523/ 32.0f);
|
||||
}
|
||||
|
||||
// skcms_TransferFunction also supports functions of the form of HLG's inverse...
|
||||
//
|
||||
// { sign(linear) * ( R|linear|^G ) when 0 <= |linear| <= 1
|
||||
// encoded = { sign(linear) * ( a ln(|linear|-b) + c ) when 1 < |linear|
|
||||
SKCMS_API bool skcms_TransferFunction_makeHLGinvish(skcms_TransferFunction*,
|
||||
float R, float G,
|
||||
float a, float b, float c);
|
||||
|
||||
// ... and of the form of HLG itself, factored to take the same five parameters.
|
||||
//
|
||||
// { sign(encoded) * ( (|encoded|/R)^(1/G) ) when 0 <= |encoded| <= R
|
||||
// linear = { sign(encoded) * ( e^( (|encoded|-c)/a ) + b ) when R < |encoded|
|
||||
SKCMS_API bool skcms_TransferFunction_makeHLGish(skcms_TransferFunction*,
|
||||
float R, float G,
|
||||
float a, float b, float c);
|
||||
|
||||
static inline bool skcms_TransferFunction_makeHLG(skcms_TransferFunction* tf) {
|
||||
return skcms_TransferFunction_makeHLGish(tf,
|
||||
0.5f, 0.5f , 0.17883277f, 0.28466892f, 0.55991073f);
|
||||
}
|
||||
static inline bool skcms_TransferFunction_makeHLGinv(skcms_TransferFunction* tf) {
|
||||
return skcms_TransferFunction_makeHLGinvish(tf,
|
||||
0.5f, 0.5f , 0.17883277f, 0.28466892f, 0.55991073f);
|
||||
}
|
||||
|
||||
// Unified representation of 'curv' or 'para' tag data, or a 1D table from 'mft1' or 'mft2'
|
||||
typedef union skcms_Curve {
|
||||
struct {
|
||||
|
101
third_party/skcms/skcms.cc
vendored
101
third_party/skcms/skcms.cc
vendored
@ -61,6 +61,80 @@ static float minus_1_ulp(float x) {
|
||||
return x;
|
||||
}
|
||||
|
||||
// Most transfer functions we work with are sRGBish.
|
||||
// For exotic HDR transfer functions, we encode them using a tf.g that makes no sense,
|
||||
// and repurpose the other fields to hold the parameters of the HDR functions.
|
||||
enum TFKind { Bad, sRGBish, PQish, HLGish, HLGinvish };
|
||||
struct TF_PQish { float A,B,C,D,E,F; };
|
||||
struct TF_HLGish { float R,G,a,b,c; };
|
||||
|
||||
static float TFKind_marker(TFKind kind) {
|
||||
// We'd use different NaNs, but those aren't guaranteed to be preserved by WASM.
|
||||
return -(float)kind;
|
||||
}
|
||||
|
||||
static TFKind classify(const skcms_TransferFunction& tf, TF_PQish* pq = nullptr
|
||||
, TF_HLGish* hlg = nullptr) {
|
||||
if (tf.g < 0 && (int)tf.g == tf.g) {
|
||||
// TODO: sanity checks for PQ/HLG like we do for sRGBish.
|
||||
switch (-(int)tf.g) {
|
||||
case PQish: if (pq ) { memcpy(pq , &tf.a, sizeof(*pq )); } return PQish;
|
||||
case HLGish: if (hlg) { memcpy(hlg, &tf.a, sizeof(*hlg)); } return HLGish;
|
||||
case HLGinvish: if (hlg) { memcpy(hlg, &tf.a, sizeof(*hlg)); } return HLGinvish;
|
||||
}
|
||||
return Bad;
|
||||
}
|
||||
|
||||
// Basic sanity checks for sRGBish transfer functions.
|
||||
if (isfinitef_(tf.a + tf.b + tf.c + tf.d + tf.e + tf.f + tf.g)
|
||||
// a,c,d,g should be non-negative to make any sense.
|
||||
&& tf.a >= 0
|
||||
&& tf.c >= 0
|
||||
&& tf.d >= 0
|
||||
&& tf.g >= 0
|
||||
// Raising a negative value to a fractional tf->g produces complex numbers.
|
||||
&& tf.a * tf.d + tf.b >= 0) {
|
||||
return sRGBish;
|
||||
}
|
||||
|
||||
return Bad;
|
||||
}
|
||||
|
||||
// TODO: temporary shim for old call sites
|
||||
static bool tf_is_valid(const skcms_TransferFunction* tf) {
|
||||
return classify(*tf) == sRGBish;
|
||||
}
|
||||
|
||||
|
||||
bool skcms_TransferFunction_makePQish(skcms_TransferFunction* tf,
|
||||
float A, float B, float C,
|
||||
float D, float E, float F) {
|
||||
*tf = { TFKind_marker(PQish), A,B,C,D,E,F };
|
||||
assert(classify(*tf) == PQish);
|
||||
return true;
|
||||
}
|
||||
|
||||
float skcms_TransferFunction_eval(const skcms_TransferFunction* tf, float x) {
|
||||
float sign = x < 0 ? -1.0f : 1.0f;
|
||||
x *= sign;
|
||||
|
||||
TF_PQish pq;
|
||||
switch (classify(*tf, &pq)) {
|
||||
case Bad: break;
|
||||
case HLGish: break;
|
||||
case HLGinvish: break;
|
||||
|
||||
case sRGBish: return sign * (x < tf->d ? tf->c * x + tf->f
|
||||
: powf_(tf->a * x + tf->b, tf->g) + tf->e);
|
||||
|
||||
case PQish: return sign * powf_(fmaxf_(pq.A + pq.B * powf_(x, pq.C), 0)
|
||||
/ (pq.D + pq.E * powf_(x, pq.C)),
|
||||
pq.F);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static float eval_curve(const skcms_Curve* curve, float x) {
|
||||
if (curve->table_entries == 0) {
|
||||
return skcms_TransferFunction_eval(&curve->parametric, x);
|
||||
@ -255,25 +329,6 @@ static bool read_to_XYZD50(const skcms_ICCTag* rXYZ, const skcms_ICCTag* gXYZ,
|
||||
read_tag_xyz(bXYZ, &toXYZ->vals[0][2], &toXYZ->vals[1][2], &toXYZ->vals[2][2]);
|
||||
}
|
||||
|
||||
static bool tf_is_valid(const skcms_TransferFunction* tf) {
|
||||
// Reject obviously malformed inputs
|
||||
if (!isfinitef_(tf->a + tf->b + tf->c + tf->d + tf->e + tf->f + tf->g)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// All of these parameters should be non-negative
|
||||
if (tf->a < 0 || tf->c < 0 || tf->d < 0 || tf->g < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// It's rather _complex_ to raise a negative number to a fractional power tf->g.
|
||||
if (tf->a * tf->d + tf->b < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint8_t type [4];
|
||||
uint8_t reserved_a [4];
|
||||
@ -1419,14 +1474,6 @@ float powf_(float x, float y) {
|
||||
: exp2f_(log2f_(x) * y);
|
||||
}
|
||||
|
||||
float skcms_TransferFunction_eval(const skcms_TransferFunction* tf, float x) {
|
||||
float sign = x < 0 ? -1.0f : 1.0f;
|
||||
x *= sign;
|
||||
|
||||
return sign * (x < tf->d ? tf->c * x + tf->f
|
||||
: powf_(tf->a * x + tf->b, tf->g) + tf->e);
|
||||
}
|
||||
|
||||
#if defined(__clang__)
|
||||
[[clang::no_sanitize("float-divide-by-zero")]] // Checked for by tf_is_valid() on the way out.
|
||||
#endif
|
||||
|
2
third_party/skcms/version.sha1
vendored
2
third_party/skcms/version.sha1
vendored
@ -1 +1 @@
|
||||
5c593bf702db07bdd782b58f9bde28e8ee67061b
|
||||
a52db47aa53f894d1fd478173c7b7c4eb0984f42
|
Loading…
Reference in New Issue
Block a user