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:
parent
8c2ee59635
commit
e5a041c068
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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())) {
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user