Implement the clip as 4 or fewer GrEffects when possible.

BUG=skia:2181
R=robertphillips@google.com

Author: bsalomon@google.com

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

git-svn-id: http://skia.googlecode.com/svn/trunk@13710 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
commit-bot@chromium.org 2014-03-07 19:43:43 +00:00
parent 8c2ee59635
commit e5a041c068
5 changed files with 136 additions and 55 deletions

View File

@ -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

View File

@ -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<GrEffectRef> 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<GrEffectRef> 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;
}

View File

@ -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,

View File

@ -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())) {

View File

@ -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;