fix bounds for BW lines, AA Hairlines
authorjoshualitt <joshualitt@chromium.org>
Wed, 13 May 2015 15:00:56 +0000 (08:00 -0700)
committerCommit bot <commit-bot@chromium.org>
Wed, 13 May 2015 15:00:56 +0000 (08:00 -0700)
BUG=skia:

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

src/gpu/GrAAHairLinePathRenderer.cpp
src/gpu/GrContext.cpp

index c5d8ae1..3508727 100644 (file)
@@ -730,6 +730,10 @@ private:
         // compute bounds
         fBounds = geometry.fPath.getBounds();
         geometry.fViewMatrix.mapRect(&fBounds);
+
+        // This is b.c. hairlines are notionally infinitely thin so without expansion
+        // two overlapping lines could be reordered even though they hit the same pixels.
+        fBounds.outset(0.5f, 0.5f);
     }
 
     bool onCombineIfPossible(GrBatch* t) override {
index e26c57f..bf62538 100755 (executable)
@@ -404,8 +404,8 @@ public:
         SkScalar fStrokeWidth;
     };
 
-    static GrBatch* Create(const Geometry& geometry) {
-        return SkNEW_ARGS(StrokeRectBatch, (geometry));
+    static GrBatch* Create(const Geometry& geometry, bool snapToPixelCenters) {
+        return SkNEW_ARGS(StrokeRectBatch, (geometry, snapToPixelCenters));
     }
 
     const char* name() const override { return "StrokeRectBatch"; }
@@ -501,7 +501,7 @@ public:
     SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
 
 private:
-    StrokeRectBatch(const Geometry& geometry) {
+    StrokeRectBatch(const Geometry& geometry, bool snapToPixelCenters) {
         this->initClassID<StrokeRectBatch>();
 
         fBatch.fHairline = geometry.fStrokeWidth == 0;
@@ -513,6 +513,11 @@ private:
         SkScalar rad = SkScalarHalf(geometry.fStrokeWidth);
         fBounds.outset(rad, rad);
         geometry.fViewMatrix.mapRect(&fBounds);
+
+        // If our caller snaps to pixel centers then we have to round out the bounds
+        if (snapToPixelCenters) {
+            fBounds.roundOut();
+        }
     }
 
     /*  create a triangle strip that strokes the specified rect. There are 8
@@ -661,13 +666,15 @@ void GrContext::drawRect(GrRenderTarget* rt,
         geometry.fRect = rect;
         geometry.fStrokeWidth = width;
 
-        SkAutoTUnref<GrBatch> batch(StrokeRectBatch::Create(geometry));
+        // Non-AA hairlines are snapped to pixel centers to make which pixels are hit deterministic
+        bool snapToPixelCenters = (0 == width && !rt->isMultisampled());
+        SkAutoTUnref<GrBatch> batch(StrokeRectBatch::Create(geometry, snapToPixelCenters));
 
         // Depending on sub-pixel coordinates and the particular GPU, we may lose a corner of
         // hairline rects. We jam all the vertices to pixel centers to avoid this, but not when MSAA
         // is enabled because it can cause ugly artifacts.
         pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_Flag,
-                                 0 == width && !rt->isMultisampled());
+                                 snapToPixelCenters);
         target->drawBatch(&pipelineBuilder, batch);
     } else {
         // filled BW rect
@@ -1008,6 +1015,12 @@ void GrContext::drawVertices(GrRenderTarget* rt,
 
     viewMatrix.mapRect(&bounds);
 
+    // If we don't have AA then we outset for a half pixel in each direction to account for
+    // snapping
+    if (!paint.isAntiAlias()) {
+        bounds.outset(0.5f, 0.5f);
+    }
+
     DrawVerticesBatch::Geometry geometry;
     geometry.fColor = paint.getColor();
     SkAutoTUnref<GrBatch> batch(DrawVerticesBatch::Create(geometry, primitiveType, viewMatrix,
@@ -1879,7 +1892,7 @@ BATCH_TEST_DEFINE(StrokeRect) {
     geometry.fRect = GrTest::TestRect(random);
     geometry.fStrokeWidth = random->nextBool() ? 0.0f : 1.0f;
 
-    return StrokeRectBatch::Create(geometry);
+    return StrokeRectBatch::Create(geometry, random->nextBool());
 }
 
 static uint32_t seed_vertices(GrPrimitiveType type) {