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_quad_effects
|
||||||
bezier_conic_effects
|
bezier_conic_effects
|
||||||
bezier_cubic_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;
|
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,
|
// sort out what kind of clip mask needs to be created: alpha, stencil,
|
||||||
// scissor, or entirely software
|
// scissor, or entirely software
|
||||||
@ -156,59 +256,27 @@ bool GrClipMaskManager::setupClipping(const GrClipData* clipDataIn,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there is only one clip element we check whether the draw's bounds are contained
|
// An element count of 4 was chosen because of the common pattern in Blink of:
|
||||||
// fully within the clip. If not, we install an effect that handles the clip for some
|
// isect RR
|
||||||
// cases.
|
// diff RR
|
||||||
if (1 == elements.count() && SkRegion::kReplace_Op == elements.tail()->getOp()) {
|
// isect convex_poly
|
||||||
if (NULL != devBounds) {
|
// isect convex_poly
|
||||||
SkRect boundsInClipSpace = *devBounds;
|
// when drawing rounded div borders. This could probably be tuned based on a
|
||||||
boundsInClipSpace.offset(SkIntToScalar(clipDataIn->fOrigin.fX),
|
// configuration's relative costs of switching RTs to generate a mask vs
|
||||||
SkIntToScalar(clipDataIn->fOrigin.fY));
|
// longer shaders.
|
||||||
if (elements.tail()->contains(boundsInClipSpace)) {
|
if (elements.count() <= 4) {
|
||||||
fGpu->disableScissor();
|
SkVector clipToRTOffset = { SkIntToScalar(-clipDataIn->fOrigin.fX),
|
||||||
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) };
|
SkIntToScalar(-clipDataIn->fOrigin.fY) };
|
||||||
effect.reset(GrConvexPolyEffect::Create(kFillBW_GrEffectEdgeType,
|
if (elements.isEmpty() ||
|
||||||
path, &offset));
|
this->installClipEffects(elements, are, clipToRTOffset, devBounds)) {
|
||||||
}
|
|
||||||
} else {
|
|
||||||
SkVector offset = { 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);
|
|
||||||
SkIRect scissorSpaceIBounds(clipSpaceIBounds);
|
SkIRect scissorSpaceIBounds(clipSpaceIBounds);
|
||||||
scissorSpaceIBounds.offset(-clipDataIn->fOrigin);
|
scissorSpaceIBounds.offset(-clipDataIn->fOrigin);
|
||||||
|
if (NULL == devBounds ||
|
||||||
|
!SkRect::Make(scissorSpaceIBounds).contains(*devBounds)) {
|
||||||
fGpu->enableScissor(scissorSpaceIBounds);
|
fGpu->enableScissor(scissorSpaceIBounds);
|
||||||
|
} else {
|
||||||
|
fGpu->disableScissor();
|
||||||
|
}
|
||||||
this->setGpuStencil();
|
this->setGpuStencil();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -105,6 +105,13 @@ private:
|
|||||||
|
|
||||||
GrClipMaskCache fAACache; // cache for the AA path
|
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
|
// Draws the clip into the stencil buffer
|
||||||
bool createStencilClipMask(int32_t elementsGenID,
|
bool createStencilClipMask(int32_t elementsGenID,
|
||||||
GrReducedClip::InitialState initialState,
|
GrReducedClip::InitialState initialState,
|
||||||
|
@ -143,8 +143,8 @@ void GLAARectEffect::emitCode(GrGLShaderBuilder* builder,
|
|||||||
builder->fsCodeAppendf("\t\tfloat alpha = 1.0;\n");
|
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.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.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.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.w - %s.y) > -0.5 ? 1.0 : 0.0;\n", rectName, fragmentPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GrEffectEdgeTypeIsInverseFill(aare.getEdgeType())) {
|
if (GrEffectEdgeTypeIsInverseFill(aare.getEdgeType())) {
|
||||||
|
@ -67,7 +67,7 @@ const SkScalar RRectEffect::kRadiusMin = 0.5f;
|
|||||||
GrEffectRef* RRectEffect::Create(GrEffectEdgeType edgeType,
|
GrEffectRef* RRectEffect::Create(GrEffectEdgeType edgeType,
|
||||||
RRectType rrType,
|
RRectType rrType,
|
||||||
const SkRRect& rrect) {
|
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))));
|
return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(RRectEffect, (edgeType, rrType, rrect))));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,7 +228,7 @@ void GLRRectEffect::emitCode(GrGLShaderBuilder* builder,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kInverseFillBW_GrEffectEdgeType == rre.getEdgeType()) {
|
if (kInverseFillAA_GrEffectEdgeType == rre.getEdgeType()) {
|
||||||
builder->fsCodeAppend("\t\talpha = 1.0 - alpha;\n");
|
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) {
|
GrEffectRef* GrRRectEffect::Create(GrEffectEdgeType edgeType, const SkRRect& rrect) {
|
||||||
if (kFillAA_GrEffectEdgeType != edgeType && kInverseFillBW_GrEffectEdgeType != edgeType) {
|
if (kFillAA_GrEffectEdgeType != edgeType && kInverseFillAA_GrEffectEdgeType != edgeType) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
RRectEffect::RRectType rrtype;
|
RRectEffect::RRectType rrtype;
|
||||||
|
Loading…
Reference in New Issue
Block a user