Update 4f linear gradient selection heuristic
authorfmalita <fmalita@chromium.org>
Tue, 23 Feb 2016 21:26:28 +0000 (13:26 -0800)
committerCommit bot <commit-bot@chromium.org>
Tue, 23 Feb 2016 21:26:28 +0000 (13:26 -0800)
Use the 4f context when

  * dest type is 4f
  * there's no perpective

Keeping the define and testing flag overrides for now.

R=reed@google.com,herb@google.com
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1725793003

Review URL: https://codereview.chromium.org/1725793003

src/effects/gradients/SkLinearGradient.cpp
tests/SkColor4fTest.cpp

index 1fbd96e..cc8875c 100644 (file)
@@ -9,7 +9,7 @@
 #include "SkLinearGradient.h"
 
 // define to test the 4f gradient path
-// #define USE_4fGRADIENTS
+// #define FORCE_4F_CONTEXT
 
 static const float kInv255Float = 1.0f / 255;
 
@@ -47,11 +47,18 @@ static SkMatrix pts_to_unit_matrix(const SkPoint pts[2]) {
     return matrix;
 }
 
-static bool use_4f_context(uint32_t flags) {
-#ifdef USE_4fGRADIENTS
+static bool use_4f_context(const SkShader::ContextRec& rec, uint32_t flags) {
+#ifdef FORCE_4F_CONTEXT
     return true;
 #else
-    return SkToBool(flags & SkLinearGradient::kForce4fContext_PrivateFlag);
+    // Perspective not supported in 4f yet.
+    if (rec.fMatrix->hasPerspective()
+        || (rec.fLocalMatrix && rec.fLocalMatrix->hasPerspective())) {
+        return false;
+    }
+
+    return rec.fPreferredDstType == SkShader::ContextRec::kPM4f_DstType
+        || SkToBool(flags & SkLinearGradient::kForce4fContext_PrivateFlag);
 #endif
 }
 
@@ -81,14 +88,14 @@ void SkLinearGradient::flatten(SkWriteBuffer& buffer) const {
     buffer.writePoint(fEnd);
 }
 
-size_t SkLinearGradient::contextSize(const ContextRec&) const {
-    return use_4f_context(fGradFlags)
+size_t SkLinearGradient::contextSize(const ContextRec& rec) const {
+    return use_4f_context(rec, fGradFlags)
         ? sizeof(LinearGradient4fContext)
         : sizeof(LinearGradientContext);
 }
 
 SkShader::Context* SkLinearGradient::onCreateContext(const ContextRec& rec, void* storage) const {
-    return use_4f_context(fGradFlags)
+    return use_4f_context(rec, fGradFlags)
         ? static_cast<SkShader::Context*>(new (storage) LinearGradient4fContext(*this, rec))
         : static_cast<SkShader::Context*>(new (storage) LinearGradientContext(*this, rec));
 }
index 00581cc..ea9a80f 100644 (file)
@@ -125,23 +125,26 @@ static SkShader* make_cf_sh() {
 }
 
 static void compare_spans(const SkPM4f span4f[], const SkPMColor span4b[], int count,
-                          skiatest::Reporter* reporter) {
+                          skiatest::Reporter* reporter, float tolerance = 1.0f/255) {
     for (int i = 0; i < count; ++i) {
         SkPM4f c0 = SkPM4f::FromPMColor(span4b[i]);
         SkPM4f c1 = span4f[i];
-        REPORTER_ASSERT(reporter, nearly_equal(c0, c1, 1.0f/255));
+        REPORTER_ASSERT(reporter, nearly_equal(c0, c1, tolerance));
     }
 }
 
 DEF_TEST(Color4f_shader, reporter) {
     struct {
-        SkShader*   (*fFact)();
-        bool        fSupports4f;
+        SkShader* (*fFact)();
+        bool      fSupports4f;
+        float     fTolerance;
     } recs[] = {
-        { make_color_sh, true },
-        { make_grad_sh,  false },
-        { make_image_sh, false },
-        { make_cf_sh,    true },
+        { make_color_sh, true,  1.0f/255   },
+        // PMColor 4f gradients are interpolated in 255-multiplied values, so we need a
+        // slightly relaxed tolerance to accommodate the cumulative precision deviation.
+        { make_grad_sh,  true,  1.001f/255 },
+        { make_image_sh, false, 1.0f/255   },
+        { make_cf_sh,    true,  1.0f/255   },
     };
 
     SkPaint paint;
@@ -161,7 +164,7 @@ DEF_TEST(Color4f_shader, reporter) {
             ctx->shadeSpan4f(0, 0, buffer4f, N);
             SkPMColor buffer4b[N];
             ctx->shadeSpan(0, 0, buffer4b, N);
-            compare_spans(buffer4f, buffer4b, N, reporter);
+            compare_spans(buffer4f, buffer4b, N, reporter, rec.fTolerance);
         }
         ctx->~Context();
     }