diff --git a/expectations/gm/ignored-tests.txt b/expectations/gm/ignored-tests.txt index dec7f8d718..e09a5ec188 100644 --- a/expectations/gm/ignored-tests.txt +++ b/expectations/gm/ignored-tests.txt @@ -42,3 +42,9 @@ inverse_paths bezier_quad_effects bezier_conic_effects bezier_cubic_effects + +# bsalomon: These tests change slightly due to https://codereview.chromium.org/188693008/ +gpu/complexclip2_rrect_aa +gpu/complexclip2_rect_aa +convex_poly_effect +rrect_effect diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp index e24c759688..96f4b209e3 100644 --- a/src/gpu/GrClipMaskManager.cpp +++ b/src/gpu/GrClipMaskManager.cpp @@ -107,6 +107,106 @@ bool GrClipMaskManager::useSWOnlyPath(const ElementList& elements) { return false; } +bool GrClipMaskManager::installClipEffects(const ElementList& elements, + GrDrawState::AutoRestoreEffects* are, + const SkVector& clipToRTOffset, + const SkRect* drawBounds) { + + GrDrawState* drawState = fGpu->drawState(); + SkRect boundsInClipSpace; + if (NULL != drawBounds) { + boundsInClipSpace = *drawBounds; + boundsInClipSpace.offset(-clipToRTOffset.fX, -clipToRTOffset.fY); + } + + are->set(drawState); + GrRenderTarget* rt = drawState->getRenderTarget(); + ElementList::Iter iter(elements); + + bool setARE = false; + bool failed = false; + + while (NULL != iter.get()) { + SkRegion::Op op = iter.get()->getOp(); + bool invert; + bool skip = false; + switch (op) { + case SkRegion::kReplace_Op: + SkASSERT(iter.get() == elements.head()); + // Fallthrough, handled same as intersect. + case SkRegion::kIntersect_Op: + invert = false; + if (NULL != drawBounds && iter.get()->contains(boundsInClipSpace)) { + skip = true; + } + break; + case SkRegion::kDifference_Op: + invert = true; + // We don't currently have a cheap test for whether a rect is fully outside an + // element's primitive, so don't attempt to set skip. + break; + default: + failed = true; + break; + } + if (failed) { + break; + } + + if (!skip) { + GrEffectEdgeType edgeType; + if (GR_AA_CLIP && iter.get()->isAA()) { + if (rt->isMultisampled()) { + // Coverage based AA clips don't place nicely with MSAA. + failed = true; + break; + } + edgeType = invert ? kInverseFillAA_GrEffectEdgeType : kFillAA_GrEffectEdgeType; + } else { + edgeType = invert ? kInverseFillBW_GrEffectEdgeType : kFillBW_GrEffectEdgeType; + } + SkAutoTUnref effect; + switch (iter.get()->getType()) { + case SkClipStack::Element::kPath_Type: + effect.reset(GrConvexPolyEffect::Create(edgeType, iter.get()->getPath(), + &clipToRTOffset)); + break; + case SkClipStack::Element::kRRect_Type: { + SkRRect rrect = iter.get()->getRRect(); + rrect.offset(clipToRTOffset.fX, clipToRTOffset.fY); + effect.reset(GrRRectEffect::Create(edgeType, rrect)); + break; + } + case SkClipStack::Element::kRect_Type: { + SkRect rect = iter.get()->getRect(); + rect.offset(clipToRTOffset.fX, clipToRTOffset.fY); + effect.reset(GrConvexPolyEffect::Create(edgeType, rect)); + break; + } + default: + break; + } + if (effect) { + if (!setARE) { + are->set(fGpu->drawState()); + setARE = true; + } + fGpu->drawState()->addCoverageEffect(effect); + } else { + failed = true; + break; + } + } + iter.next(); + } + + if (failed) { + are->set(NULL); + } + + return !failed; +} + //////////////////////////////////////////////////////////////////////////////// // sort out what kind of clip mask needs to be created: alpha, stencil, // scissor, or entirely software @@ -156,59 +256,27 @@ bool GrClipMaskManager::setupClipping(const GrClipData* clipDataIn, return true; } - // If there is only one clip element we check whether the draw's bounds are contained - // fully within the clip. If not, we install an effect that handles the clip for some - // cases. - if (1 == elements.count() && SkRegion::kReplace_Op == elements.tail()->getOp()) { - if (NULL != devBounds) { - SkRect boundsInClipSpace = *devBounds; - boundsInClipSpace.offset(SkIntToScalar(clipDataIn->fOrigin.fX), - SkIntToScalar(clipDataIn->fOrigin.fY)); - if (elements.tail()->contains(boundsInClipSpace)) { - fGpu->disableScissor(); - this->setGpuStencil(); - return true; - } - } - Element::Type type = elements.tail()->getType(); - bool isAA = GR_AA_CLIP && elements.tail()->isAA(); - SkAutoTUnref effect; - if (SkClipStack::Element::kPath_Type == type) { - const SkPath& path = elements.tail()->getPath(); - if (rt->isMultisampled()) { - // A coverage effect for AA clipping won't play nicely with MSAA. - if (!isAA) { - SkVector offset = { SkIntToScalar(-clipDataIn->fOrigin.fX), - SkIntToScalar(-clipDataIn->fOrigin.fY) }; - effect.reset(GrConvexPolyEffect::Create(kFillBW_GrEffectEdgeType, - path, &offset)); - } - } else { - SkVector offset = { SkIntToScalar(-clipDataIn->fOrigin.fX), + // An element count of 4 was chosen because of the common pattern in Blink of: + // isect RR + // diff RR + // isect convex_poly + // isect convex_poly + // when drawing rounded div borders. This could probably be tuned based on a + // configuration's relative costs of switching RTs to generate a mask vs + // longer shaders. + if (elements.count() <= 4) { + SkVector clipToRTOffset = { SkIntToScalar(-clipDataIn->fOrigin.fX), SkIntToScalar(-clipDataIn->fOrigin.fY) }; - GrEffectEdgeType type = isAA ? kFillAA_GrEffectEdgeType : kFillBW_GrEffectEdgeType; - effect.reset(GrConvexPolyEffect::Create(type, path, &offset)); - } - } else if (isAA && SkClipStack::Element::kRRect_Type == type && !rt->isMultisampled()) { - const SkRRect& rrect = elements.tail()->getRRect(); - effect.reset(GrRRectEffect::Create(kFillAA_GrEffectEdgeType, rrect)); - } else if (isAA && SkClipStack::Element::kRect_Type == type && !rt->isMultisampled()) { - // We only handle AA/non-MSAA rects here. Coverage effect AA isn't MSAA friendly and - // non-AA rect clips are handled by the scissor. - SkRect rect = elements.tail()->getRect(); - SkVector offset = { SkIntToScalar(-clipDataIn->fOrigin.fX), - SkIntToScalar(-clipDataIn->fOrigin.fY) }; - rect.offset(offset); - effect.reset(GrConvexPolyEffect::Create(kFillAA_GrEffectEdgeType, rect)); - // This should never fail. - SkASSERT(effect); - } - if (effect) { - are->set(fGpu->drawState()); - fGpu->drawState()->addCoverageEffect(effect); + if (elements.isEmpty() || + this->installClipEffects(elements, are, clipToRTOffset, devBounds)) { SkIRect scissorSpaceIBounds(clipSpaceIBounds); scissorSpaceIBounds.offset(-clipDataIn->fOrigin); - fGpu->enableScissor(scissorSpaceIBounds); + if (NULL == devBounds || + !SkRect::Make(scissorSpaceIBounds).contains(*devBounds)) { + fGpu->enableScissor(scissorSpaceIBounds); + } else { + fGpu->disableScissor(); + } this->setGpuStencil(); return true; } diff --git a/src/gpu/GrClipMaskManager.h b/src/gpu/GrClipMaskManager.h index 3d34fb9555..17329108b3 100644 --- a/src/gpu/GrClipMaskManager.h +++ b/src/gpu/GrClipMaskManager.h @@ -105,6 +105,13 @@ private: GrClipMaskCache fAACache; // cache for the AA path + // Attempts to install a series of coverage effects to implement the clip. Return indicates + // whether the element list was successfully converted to effects. + bool installClipEffects(const GrReducedClip::ElementList&, + GrDrawState::AutoRestoreEffects*, + const SkVector& clipOffset, + const SkRect* devBounds); + // Draws the clip into the stencil buffer bool createStencilClipMask(int32_t elementsGenID, GrReducedClip::InitialState initialState, diff --git a/src/gpu/effects/GrConvexPolyEffect.cpp b/src/gpu/effects/GrConvexPolyEffect.cpp index 0793befb57..d24b45e10b 100644 --- a/src/gpu/effects/GrConvexPolyEffect.cpp +++ b/src/gpu/effects/GrConvexPolyEffect.cpp @@ -143,8 +143,8 @@ void GLAARectEffect::emitCode(GrGLShaderBuilder* builder, builder->fsCodeAppendf("\t\tfloat alpha = 1.0;\n"); builder->fsCodeAppendf("\t\talpha *= (%s.x - %s.x) > -0.5 ? 1.0 : 0.0;\n", fragmentPos, rectName); builder->fsCodeAppendf("\t\talpha *= (%s.z - %s.x) > -0.5 ? 1.0 : 0.0;\n", rectName, fragmentPos); - builder->fsCodeAppendf("\t\talpha *= (%s.y - %s.y) > 0.5 ? 1.0 : 0.0;\n", fragmentPos, rectName); - builder->fsCodeAppendf("\t\talpha *= (%s.w - %s.y) > 0.5 ? 1.0 : 0.0;\n", rectName, fragmentPos); + builder->fsCodeAppendf("\t\talpha *= (%s.y - %s.y) > -0.5 ? 1.0 : 0.0;\n", fragmentPos, rectName); + builder->fsCodeAppendf("\t\talpha *= (%s.w - %s.y) > -0.5 ? 1.0 : 0.0;\n", rectName, fragmentPos); } if (GrEffectEdgeTypeIsInverseFill(aare.getEdgeType())) { diff --git a/src/gpu/effects/GrRRectEffect.cpp b/src/gpu/effects/GrRRectEffect.cpp index 5b755b350f..bc6abea547 100644 --- a/src/gpu/effects/GrRRectEffect.cpp +++ b/src/gpu/effects/GrRRectEffect.cpp @@ -67,7 +67,7 @@ const SkScalar RRectEffect::kRadiusMin = 0.5f; GrEffectRef* RRectEffect::Create(GrEffectEdgeType edgeType, RRectType rrType, const SkRRect& rrect) { - SkASSERT(kFillAA_GrEffectEdgeType == edgeType || kInverseFillBW_GrEffectEdgeType == edgeType); + SkASSERT(kFillAA_GrEffectEdgeType == edgeType || kInverseFillAA_GrEffectEdgeType == edgeType); return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(RRectEffect, (edgeType, rrType, rrect)))); } @@ -228,7 +228,7 @@ void GLRRectEffect::emitCode(GrGLShaderBuilder* builder, break; } - if (kInverseFillBW_GrEffectEdgeType == rre.getEdgeType()) { + if (kInverseFillAA_GrEffectEdgeType == rre.getEdgeType()) { builder->fsCodeAppend("\t\talpha = 1.0 - alpha;\n"); } @@ -293,7 +293,7 @@ void GLRRectEffect::setData(const GrGLUniformManager& uman, const GrDrawEffect& ////////////////////////////////////////////////////////////////////////////// GrEffectRef* GrRRectEffect::Create(GrEffectEdgeType edgeType, const SkRRect& rrect) { - if (kFillAA_GrEffectEdgeType != edgeType && kInverseFillBW_GrEffectEdgeType != edgeType) { + if (kFillAA_GrEffectEdgeType != edgeType && kInverseFillAA_GrEffectEdgeType != edgeType) { return NULL; } RRectEffect::RRectType rrtype;