remove to_2dot2 and from_2dot2

The parametric_{r,g,b} stages are just as good now;
under the hood it's all going through approx_powf.

Change-Id: If7f3ae1e24fcee2ddb201c1d66ce1dd64820c89a
Reviewed-on: https://skia-review.googlesource.com/14320
Reviewed-by: Matt Sarett <msarett@google.com>
Commit-Queue: Mike Klein <mtklein@chromium.org>
This commit is contained in:
Mike Klein 2017-04-25 15:51:23 -04:00 committed by Skia Commit-Bot
parent 21c131395f
commit c7be00366b
8 changed files with 690 additions and 3331 deletions

View File

@ -91,6 +91,13 @@ public:
};
DEF_BENCH( return (new SkRasterPipelineLegacyBench); )
static SkColorSpaceTransferFn gamma(float g) {
SkColorSpaceTransferFn fn = {0,0,0,0,0,0,0};
fn.fG = g;
fn.fA = 1;
return fn;
}
class SkRasterPipeline_2dot2 : public Benchmark {
public:
bool isSuitableFor(Backend backend) override { return backend == kNonRendering_Backend; }
@ -100,10 +107,17 @@ public:
void onDraw(int loops, SkCanvas*) override {
SkColor4f c = { 1.0f, 1.0f, 1.0f, 1.0f };
SkColorSpaceTransferFn from_2dot2 = gamma( 2.2f),
to_2dot2 = gamma(1/2.2f);
SkRasterPipeline p;
p.append(SkRasterPipeline::constant_color, &c);
p.append(SkRasterPipeline::from_2dot2);
p.append(SkRasterPipeline::to_2dot2);
p.append(SkRasterPipeline::parametric_r, &from_2dot2);
p.append(SkRasterPipeline::parametric_g, &from_2dot2);
p.append(SkRasterPipeline::parametric_b, &from_2dot2);
p.append(SkRasterPipeline::parametric_r, & to_2dot2);
p.append(SkRasterPipeline::parametric_g, & to_2dot2);
p.append(SkRasterPipeline::parametric_b, & to_2dot2);
while (loops --> 0) {
p.run(0,N);

View File

@ -1244,12 +1244,17 @@ bool SkColorSpaceXform_XYZ<kCSM>
}
TablesContext tables;
SkColorSpaceTransferFn to_2dot2 = {0,0,0,0,0,0,0};
to_2dot2.fG = 1/2.2f;
to_2dot2.fA = 1;
switch (fDstGamma) {
case kSRGB_DstGamma:
pipeline.append(SkRasterPipeline::to_srgb);
break;
case k2Dot2_DstGamma:
pipeline.append(SkRasterPipeline::to_2dot2);
pipeline.append(SkRasterPipeline::parametric_r, &to_2dot2);
pipeline.append(SkRasterPipeline::parametric_g, &to_2dot2);
pipeline.append(SkRasterPipeline::parametric_b, &to_2dot2);
break;
case kTable_DstGamma:
tables.fR = fDstGammaTables[0];

View File

@ -112,13 +112,22 @@ SkColorSpaceXform_A2B::SkColorSpaceXform_A2B(SkColorSpace_A2B* srcSpace,
case SkColorSpace_Base::kRGB_ICCTypeFlag:
currentChannels = 3;
break;
case SkColorSpace_Base::kCMYK_ICCTypeFlag:
case SkColorSpace_Base::kCMYK_ICCTypeFlag: {
currentChannels = 4;
// CMYK images from JPEGs (the only format that supports it) are actually
// inverted CMYK, so we need to invert every channel.
// TransferFn is y = -x + 1 for x < 1.f, otherwise 0x + 0, ie y = 1 - x for x in [0,1]
this->addTransferFns({1.f, 0.f, 0.f, -1.f, 1.f, 0.f, 1.f}, 4);
SkColorSpaceTransferFn fn = {0,0,0,0,0,0,0};
fn.fG = 1;
fn.fA = 0;
fn.fB = 0;
fn.fC = -1;
fn.fD = 1;
fn.fE = 0;
fn.fF = 1;
this->addTransferFns(fn,4);
break;
}
default:
currentChannels = 0;
SkASSERT(false);
@ -134,18 +143,12 @@ SkColorSpaceXform_A2B::SkColorSpaceXform_A2B(SkColorSpace_A2B* srcSpace,
break;
}
// take the fast path for 3-channel named gammas
if (3 == currentChannels) {
if (k2Dot2Curve_SkGammaNamed == e.gammaNamed()) {
SkCSXformPrintf("fast path from 2.2\n");
fElementsPipeline.append(SkRasterPipeline::from_2dot2);
break;
} else if (kSRGB_SkGammaNamed == e.gammaNamed()) {
SkCSXformPrintf("fast path from sRGB\n");
// Images should always start the pipeline as unpremul
fElementsPipeline.append_from_srgb(kUnpremul_SkAlphaType);
break;
}
// Take the fast path for ordinary sRGB.
if (3 == currentChannels && kSRGB_SkGammaNamed == e.gammaNamed()) {
SkCSXformPrintf("fast path from sRGB\n");
// Images should always start the pipeline as unpremul
fElementsPipeline.append_from_srgb(kUnpremul_SkAlphaType);
break;
}
SkCSXformPrintf("Gamma stage added: %s\n", debugGammaNamed[(int)e.gammaNamed()]);
@ -234,9 +237,16 @@ SkColorSpaceXform_A2B::SkColorSpaceXform_A2B(SkColorSpace_A2B* srcSpace,
case kLinear_SkGammaNamed:
// do nothing
break;
case k2Dot2Curve_SkGammaNamed:
fElementsPipeline.append(SkRasterPipeline::to_2dot2);
case k2Dot2Curve_SkGammaNamed: {
SkColorSpaceTransferFn fn = {0,0,0,0,0,0,0};
fn.fG = 1/2.2f;
fn.fA = 1;
auto to_2dot2 = this->copy(fn);
fElementsPipeline.append(SkRasterPipeline::parametric_r, to_2dot2);
fElementsPipeline.append(SkRasterPipeline::parametric_g, to_2dot2);
fElementsPipeline.append(SkRasterPipeline::parametric_b, to_2dot2);
break;
}
case kSRGB_SkGammaNamed:
fElementsPipeline.append(SkRasterPipeline::to_srgb);
break;

View File

@ -62,7 +62,6 @@
M(unpremul) M(premul) \
M(set_rgb) M(swap_rb) \
M(from_srgb) M(to_srgb) \
M(from_2dot2) M(to_2dot2) \
M(constant_color) M(seed_shader) \
M(load_a8) M(store_a8) \
M(load_g8) \

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -479,17 +479,6 @@ STAGE(to_srgb) {
b = fn(b);
}
STAGE(from_2dot2) {
r = approx_powf(r, C(2.2f));
g = approx_powf(g, C(2.2f));
b = approx_powf(b, C(2.2f));
}
STAGE(to_2dot2) {
r = approx_powf(r, C(1/2.2f));
g = approx_powf(g, C(1/2.2f));
b = approx_powf(b, C(1/2.2f));
}
STAGE(rgb_to_hsl) {
F mx = max(max(r,g), b),
mn = min(min(r,g), b),

View File

@ -41,7 +41,10 @@ static void check_error(skiatest::Reporter* r, float limit, SkColorSpaceTransfer
}
static void check_error(skiatest::Reporter* r, float limit, float gamma) {
check_error(r, limit, { gamma, 1.0f,0,0,0,0,0 });
SkColorSpaceTransferFn fn = {0,0,0,0,0,0,0};
fn.fG = gamma;
fn.fA = 1;
check_error(r, limit, fn);
}
DEF_TEST(Parametric_sRGB, r) {
@ -73,36 +76,3 @@ DEF_TEST(Parametric_inv_1dot8, r) { check_error(r, 1/510.0f, 1/1.8f); }
DEF_TEST(Parametric_inv_2dot0, r) { check_error(r, 1/510.0f, 1/2.0f); }
DEF_TEST(Parametric_inv_2dot2, r) { check_error(r, 1/510.0f, 1/2.2f); }
DEF_TEST(Parametric_inv_2dot4, r) { check_error(r, 1/510.0f, 1/2.4f); }
// As above, checking that the stage implements gamma within limit.
static void check_error(skiatest::Reporter* r, float limit,
float gamma, SkRasterPipeline::StockStage stage) {
// We expect the gamma will only be applied to R,G,B, leaving A alone.
// So this isn't quite exhaustive, but it's pretty good.
float in[256], out[256];
for (int i = 0; i < 256; i++) {
in [i] = i / 255.0f;
out[i] = 0.0f; // Not likely important. Just being tidy.
}
const float* ip = in;
float* op = out;
SkRasterPipeline p;
p.append(SkRasterPipeline::load_f32, &ip);
p.append(stage);
p.append(SkRasterPipeline::store_f32, &op);
p.run(0, 256/4);
for (int i = 0; i < 256; i++) {
float want = powf(i/255.0f, (i%4) == 3 ? 1.0f
: gamma);
float err = fabsf(out[i] - want);
if (err > limit) {
ERRORF(r, "At %d, error was %g (got %g, want %g)", i, err, out[i], want);
}
}
}
DEF_TEST(from_2dot2, r) { check_error(r, 1/510.f, 2.2f, SkRasterPipeline::from_2dot2); }
DEF_TEST( to_2dot2, r) { check_error(r, 1/510.f, 1/2.2f,SkRasterPipeline:: to_2dot2); }