diff options
author | 2015-07-16 07:01:39 -0700 | |
---|---|---|
committer | 2015-07-16 07:01:40 -0700 | |
commit | 767d273ea0948e4f61d318bec58ce417cdc470df (patch) | |
tree | 2fbdd42be5a05f32f8300c4adbe9ddaed2d9e3dd | |
parent | 6fb0b6779e40ce05c20cf279f0ecff31fa3cd60d (diff) |
Replace buggy_blend_modes GM with an exhaustive test.
The new test is disabled by default, as it's quite slow.
We can run it if we suspect problems by passing -x to DM.
This test would have been failing before the bug fix, and now is passing.
Assuming the Priv on the end means it's not considered public API...
TBR=reed@google.com
BUG=skia:4052
Review URL: https://codereview.chromium.org/1228333003
-rw-r--r-- | gm/buggy_blend_modes.cpp | 52 | ||||
-rw-r--r-- | include/core/SkColorPriv.h | 12 | ||||
-rw-r--r-- | tests/BlendTest.cpp | 43 |
3 files changed, 55 insertions, 52 deletions
diff --git a/gm/buggy_blend_modes.cpp b/gm/buggy_blend_modes.cpp deleted file mode 100644 index 21a6798fe0..0000000000 --- a/gm/buggy_blend_modes.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkCanvas.h" -#include "SkGradientShader.h" -#include "gm.h" - -// This GM reproduces what I think are overflow bugs in the CPU implementations of a -// couple xfermodes. I've marked non-obvious keys to reproducing the bug // Essential! -DEF_SIMPLE_GM(buggy_blend_modes, canvas, 800, 200) { - const auto tiling = SkShader::kClamp_TileMode; - const auto flags = SkGradientShader::kInterpolateColorsInPremul_Flag; // Essential! - - SkAutoTUnref<SkShader> cyanH, magentaV; - { - SkPoint pts[] = { {0,0}, {200, 0} }; - SkColor colors[] = { 0x00000000, 0xFF00FFFF }; - cyanH.reset( - SkGradientShader::CreateLinear(pts, colors, nullptr, 2, tiling, flags, nullptr)); - } - { - SkPoint pts[] = { {0,0}, {0, 200} }; - SkColor colors[] = { 0x00000000, 0xFFFF00FF }; - magentaV.reset( - SkGradientShader::CreateLinear(pts, colors, nullptr, 2, tiling, flags, nullptr)); - } - - SkXfermode::Mode modes[] = { - SkXfermode::kDarken_Mode, // Looks ok? - SkXfermode::kHardLight_Mode, // Definitely wrong. - SkXfermode::kLighten_Mode, // Definitely wrong. - SkXfermode::kOverlay_Mode, // Same code as kHardLight_Mode. - }; - - canvas->clear(SK_ColorWHITE); - for (auto mode : modes) { - canvas->saveLayer(nullptr, nullptr); // Essential! - SkPaint h, v; - h.setShader(cyanH); - v.setShader(magentaV); - v.setXfermodeMode(mode); - canvas->drawRect(SkRect::MakeWH(200,200), h); - canvas->drawRect(SkRect::MakeWH(200,200), v); - canvas->restore(); - - canvas->translate(200, 0); - } -} diff --git a/include/core/SkColorPriv.h b/include/core/SkColorPriv.h index 15c94ac68c..f9c5d928a0 100644 --- a/include/core/SkColorPriv.h +++ b/include/core/SkColorPriv.h @@ -369,6 +369,18 @@ static inline void SkBlendRGB16(const uint16_t src[], uint16_t dst[], #define SkPMColorAssert(c) #endif +static inline bool SkPMColorValid(SkPMColor c) { + auto a = SkGetPackedA32(c); + bool valid = a <= SK_A32_MASK + && SkGetPackedR32(c) <= a + && SkGetPackedG32(c) <= a + && SkGetPackedB32(c) <= a; + if (valid) { + SkPMColorAssert(c); // Make sure we're consistent when it counts. + } + return valid; +} + /** * Pack the components into a SkPMColor, checking (in the debug version) that * the components are 0..255, and are already premultiplied (i.e. alpha >= color) diff --git a/tests/BlendTest.cpp b/tests/BlendTest.cpp index a0a84d7a7b..d816b72250 100644 --- a/tests/BlendTest.cpp +++ b/tests/BlendTest.cpp @@ -1,5 +1,15 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + #include "Test.h" #include "SkColor.h" +#include "SkColorPriv.h" +#include "SkTaskGroup.h" +#include "SkXfermode.h" #define ASSERT(x) REPORTER_ASSERT(r, x) @@ -256,3 +266,36 @@ DEF_TEST(Blend_dst_Exhaustive, r) { // all others // // Algorithms that make sense to use in Skia: blend_256_round, blend_256_round_alt, blend_perfect + +DEF_TEST(Blend_premul_begets_premul, r) { + // This test is quite slow, even if you have enough cores to run each mode in parallel. + if (!r->allowExtendedTest()) { + return; + } + + // No matter what xfermode we use, premul inputs should create premul outputs. + auto test_mode = [&](int m) { + SkXfermode::Mode mode = (SkXfermode::Mode)m; + if (mode == SkXfermode::kSrcOver_Mode) { + return; // TODO: can't create a SrcOver xfermode. + } + SkAutoTUnref<SkXfermode> xfermode(SkXfermode::Create(mode)); + SkASSERT(xfermode); + // We'll test all alphas and legal color values, assuming all colors work the same. + // This is not true for non-separable blend modes, but this test still can't hurt. + for (int sa = 0; sa <= 255; sa++) { + for (int da = 0; da <= 255; da++) { + for (int s = 0; s <= sa; s++) { + for (int d = 0; d <= da; d++) { + SkPMColor src = SkPackARGB32(sa, s, s, s), + dst = SkPackARGB32(da, d, d, d); + xfermode->xfer32(&dst, &src, 1, nullptr); // To keep it simple, no AA. + if (!SkPMColorValid(dst)) { + ERRORF(r, "%08x is not premul using %s", dst, SkXfermode::ModeName(mode)); + } + }}}} + }; + + // Parallelism helps speed things up on my desktop from ~725s to ~50s. + sk_parallel_for(SkXfermode::kLastMode, test_mode); +} |