aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar mtklein <mtklein@chromium.org>2015-07-16 07:01:39 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-07-16 07:01:40 -0700
commit767d273ea0948e4f61d318bec58ce417cdc470df (patch)
tree2fbdd42be5a05f32f8300c4adbe9ddaed2d9e3dd
parent6fb0b6779e40ce05c20cf279f0ecff31fa3cd60d (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.cpp52
-rw-r--r--include/core/SkColorPriv.h12
-rw-r--r--tests/BlendTest.cpp43
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);
+}