add {parametric,table}_{r,g,b} stages.

Think you can take over from here, hook these into SkColorSpaceXform_A2B, and remove the need for fn_1_{r,g,b}?

BUG=skia:664864

GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=4888
CQ_INCLUDE_TRYBOTS=master.client.skia:Test-Ubuntu-GCC-GCE-CPU-AVX2-x86_64-Release-SKNX_NO_SIMD-Trybot

Change-Id: If573fa2861f32f201f4db28598559290b1eef812
Reviewed-on: https://skia-review.googlesource.com/4888
Commit-Queue: Mike Klein <mtklein@chromium.org>
Reviewed-by: Matt Sarett <msarett@google.com>
diff --git a/src/core/SkRasterPipeline.h b/src/core/SkRasterPipeline.h
index 45576a3..3269a16 100644
--- a/src/core/SkRasterPipeline.h
+++ b/src/core/SkRasterPipeline.h
@@ -72,6 +72,8 @@
     M(exclusion) M(hardlight) M(lighten) M(overlay) M(softlight) \
     M(luminance_to_alpha) M(matrix_3x4) M(matrix_4x5)            \
     M(fn_1_r) M(fn_1_g) M(fn_1_b)                                \
+    M(parametric_r) M(parametric_g) M(parametric_b)              \
+    M(table_r) M(table_g) M(table_b)                             \
     M(color_lookup_table) M(lab_to_xyz) M(swap_rb)
 
 class SkRasterPipeline {
diff --git a/src/opts/SkRasterPipeline_opts.h b/src/opts/SkRasterPipeline_opts.h
index 4584f3d..b90faf8 100644
--- a/src/opts/SkRasterPipeline_opts.h
+++ b/src/opts/SkRasterPipeline_opts.h
@@ -543,6 +543,46 @@
     a = A;
 }
 
+SI SkNf parametric(const SkNf& v, const SkColorSpaceTransferFn& p) {
+    float result[N];   // Unconstrained powf() doesn't vectorize well...
+    for (int i = 0; i < N; i++) {
+        float s = v[i];
+        result[i] = (s <= p.fD) ? p.fE * s + p.fF
+                                : powf(s * p.fA + p.fB, p.fG) + p.fC;
+    }
+    return SkNf::Load(result);
+}
+
+STAGE(parametric_r, true) {
+    r = parametric(r, *(const SkColorSpaceTransferFn*)ctx);
+}
+STAGE(parametric_g, true) {
+    g = parametric(g, *(const SkColorSpaceTransferFn*)ctx);
+}
+STAGE(parametric_b, true) {
+    b = parametric(b, *(const SkColorSpaceTransferFn*)ctx);
+}
+
+SI SkNf table(const SkNf& v, const float t[1024]) {
+    SkNi ix = SkNx_cast<int>(SkNf::Max(0, SkNf::Min(v, 1)) * 1023 + 0.5);
+
+    float result[N];   // TODO: vgatherdps?
+    for (int i = 0; i < N; i++) {
+        result[i] = t[ix[i]];
+    }
+    return SkNf::Load(result);
+}
+
+STAGE(table_r, true) {
+    r = table(r, (const float*)ctx);
+}
+STAGE(table_g, true) {
+    g = table(g, (const float*)ctx);
+}
+STAGE(table_b, true) {
+    b = table(b, (const float*)ctx);
+}
+
 STAGE(fn_1_r, true) {
     auto fn = (const std::function<float(float)>*)ctx;
     float result[N];