From db4758c75fdd30ef58096c685e2d749aacaf3d92 Mon Sep 17 00:00:00 2001 From: bsalomon Date: Mon, 23 Nov 2015 11:14:20 -0800 Subject: [PATCH] Restrict query bounds for reduce clip to dev bounds Review URL: https://codereview.chromium.org/1467253002 --- src/gpu/GrClipMaskManager.cpp | 12 +++++++++++- src/gpu/GrDrawContext.cpp | 6 ++++-- src/gpu/GrDrawTarget.cpp | 2 ++ src/gpu/GrReducedClip.cpp | 7 +++---- .../batches/GrAALinearizingConvexPathRenderer.cpp | 9 +++++++++ src/gpu/batches/GrBatch.h | 4 ++++ src/gpu/batches/GrTessellatingPathRenderer.cpp | 14 +++++++++++--- 7 files changed, 44 insertions(+), 10 deletions(-) diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp index 9b78cdfdda..fa9d189e8c 100644 --- a/src/gpu/GrClipMaskManager.cpp +++ b/src/gpu/GrClipMaskManager.cpp @@ -317,8 +317,18 @@ bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder, } case GrClip::kClipStack_ClipType: { clipSpaceRTIBounds.offset(clip.origin()); + SkIRect clipSpaceReduceQueryBounds; + if (devBounds) { + SkIRect devIBounds = devBounds->roundOut(); + devIBounds.offset(clip.origin()); + if (!clipSpaceReduceQueryBounds.intersect(clipSpaceRTIBounds, devIBounds)) { + return false; + } + } else { + clipSpaceReduceQueryBounds = clipSpaceRTIBounds; + } GrReducedClip::ReduceClipStack(*clip.clipStack(), - clipSpaceRTIBounds, + clipSpaceReduceQueryBounds, &elements, &genID, &initialState, diff --git a/src/gpu/GrDrawContext.cpp b/src/gpu/GrDrawContext.cpp index 6718699c9a..1137c57bc4 100644 --- a/src/gpu/GrDrawContext.cpp +++ b/src/gpu/GrDrawContext.cpp @@ -409,8 +409,10 @@ void GrDrawContext::drawVertices(const GrClip& clip, 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()) { + // snapping. We also do this for the "hair" primitive types: lines and points since they have + // a 1 pixel thickness in device space. + if (!paint.isAntiAlias() || GrIsPrimTypeLines(primitiveType) || + kPoints_GrPrimitiveType == primitiveType) { bounds.outset(0.5f, 0.5f); } diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp index f2ed17c135..062a42fc5b 100644 --- a/src/gpu/GrDrawTarget.cpp +++ b/src/gpu/GrDrawTarget.cpp @@ -508,6 +508,8 @@ void GrDrawTarget::recordBatch(GrBatch* batch) { return; } // Stop going backwards if we would cause a painter's order violation. + // TODO: The bounds used here do not fully consider the clip. It may be advantageous + // to clip each batch's bounds to the clip. if (intersect(candidate->bounds(), batch->bounds())) { GrBATCH_INFO("\t\tIntersects with (%s, B%u)\n", candidate->name(), candidate->uniqueID()); diff --git a/src/gpu/GrReducedClip.cpp b/src/gpu/GrReducedClip.cpp index 9a6a6149ad..cbfd896002 100644 --- a/src/gpu/GrReducedClip.cpp +++ b/src/gpu/GrReducedClip.cpp @@ -416,10 +416,9 @@ void GrReducedClip::ReduceClipStack(const SkClipStack& stack, } else { if (stackBounds.contains(scalarQueryBounds)) { *initialState = kAllOut_InitialState; - if (requiresAA) { - *requiresAA = false; - } - return; + // We know that the bounding box contains all the pixels that are outside the clip, + // but we don't know that *all* the pixels in the box are outside the clip. So + // proceed to walking the stack. } if (tighterBounds) { *tighterBounds = queryBounds; diff --git a/src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp b/src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp index e6cf035ce6..659f9d4adf 100644 --- a/src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp +++ b/src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp @@ -264,6 +264,15 @@ private: // compute bounds fBounds = geometry.fPath.getBounds(); + SkScalar w = geometry.fStrokeWidth; + if (w > 0) { + w /= 2; + // If the miter limit is < 1 then we effectively fallback to bevel joins. + if (SkPaint::kMiter_Join == geometry.fJoin && w > 1.f) { + w *= geometry.fMiterLimit; + } + fBounds.outset(w, w); + } geometry.fViewMatrix.mapRect(&fBounds); } diff --git a/src/gpu/batches/GrBatch.h b/src/gpu/batches/GrBatch.h index c5fc80c5d5..03e396a29c 100644 --- a/src/gpu/batches/GrBatch.h +++ b/src/gpu/batches/GrBatch.h @@ -31,6 +31,10 @@ class GrBatchFlushState; * If there are any possible optimizations which might require knowing more about the full state of * the draw, ie whether or not the GrBatch is allowed to tweak alpha for coverage, then this * information will be communicated to the GrBatch prior to geometry generation. + * + * The bounds of the batch must contain all the vertices in device space *irrespective* of the clip. + * The bounds are used in determining which clip elements must be applied and thus the bounds cannot + * in turn depend upon the clip. */ #define GR_BATCH_SPEW 0 #if GR_BATCH_SPEW diff --git a/src/gpu/batches/GrTessellatingPathRenderer.cpp b/src/gpu/batches/GrTessellatingPathRenderer.cpp index 901d38369c..a3a888302a 100644 --- a/src/gpu/batches/GrTessellatingPathRenderer.cpp +++ b/src/gpu/batches/GrTessellatingPathRenderer.cpp @@ -1592,9 +1592,17 @@ private: , fColor(color) , fPath(path) , fStroke(stroke) - , fViewMatrix(viewMatrix) - , fClipBounds(clipBounds) { - fBounds = path.getBounds(); + , fViewMatrix(viewMatrix) { + const SkRect& pathBounds = path.getBounds(); + fClipBounds = clipBounds; + // Because the clip bounds are used to add a contour for inverse fills, they must also + // include the path bounds. + fClipBounds.join(pathBounds); + if (path.isInverseFillType()) { + fBounds = fClipBounds; + } else { + fBounds = path.getBounds(); + } if (!stroke.isFillStyle()) { SkScalar radius = SkScalarHalf(stroke.getWidth()); if (stroke.getJoin() == SkPaint::kMiter_Join) {