Specialize GrConvexPolyEffect for AA rects, use for AA clip rects.

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

Author: bsalomon@google.com

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

git-svn-id: http://skia.googlecode.com/svn/trunk@13375 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
commit-bot@chromium.org 2014-02-08 19:31:05 +00:00
parent fffc9dcf57
commit f053980016
6 changed files with 249 additions and 23 deletions

View File

@ -35,6 +35,12 @@
# Added by bsalomon for skbug.com/2051, https://codereview.chromium.org/151523005
filltypespersp
# Added by bsalomon for skbug.com/2051, https://codereview.chromium.org/140093004/
complexclip2_rect_aa
aaclip
simpleaaclip_rect
convex_poly_clip
convex_poly_effect
# Need to rebaseline all platforms, as the content was changed to remove
# deprecated calling pattern.

View File

@ -44,7 +44,7 @@ protected:
}
virtual SkISize onISize() SK_OVERRIDE {
return make_isize(475, 530);
return make_isize(475, 800);
}
virtual uint32_t onGetFlags() const SK_OVERRIDE {
@ -85,6 +85,22 @@ protected:
scaleM.setScale(1.1f, 0.4f);
ngon.transform(scaleM);
fPaths.addToTail(ngon);
// integer edges
fRects.addToTail(SkRect::MakeLTRB(5.f, 1.f, 30.f, 25.f));
// half-integer edges
fRects.addToTail(SkRect::MakeLTRB(5.5f, 0.5f, 29.5f, 24.5f));
// vertically/horizontally thin rects that cover pixel centers
fRects.addToTail(SkRect::MakeLTRB(5.25f, 0.5f, 5.75f, 24.5f));
fRects.addToTail(SkRect::MakeLTRB(5.5f, 0.5f, 29.5f, 0.75f));
// vertically/horizontally thin rects that don't cover pixel centers
fRects.addToTail(SkRect::MakeLTRB(5.55f, 0.5f, 5.75f, 24.5f));
fRects.addToTail(SkRect::MakeLTRB(5.5f, .05f, 29.5f, .25f));
// small in x and y
fRects.addToTail(SkRect::MakeLTRB(5.05f, .55f, 5.45f, .85f));
// inverted in x and y
fRects.addToTail(SkRect::MakeLTRB(100.f, 50.5f, 5.f, 0.5f));
}
virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
@ -98,11 +114,11 @@ protected:
return;
}
const SkPath* path;
SkScalar y = 0;
for (SkTLList<SkPath>::Iter iter(fPaths, SkTLList<SkPath>::Iter::kHead_IterStart);
NULL != (path = iter.get());
NULL != iter.get();
iter.next()) {
const SkPath* path = iter.get();
SkScalar x = 0;
for (int et = 0; et < GrConvexPolyEffect::kEdgeTypeCnt; ++et) {
@ -142,7 +158,7 @@ protected:
tt.target()->setIndexSourceToBuffer(context->getQuadIndexBuffer());
tt.target()->drawIndexed(kTriangleFan_GrPrimitiveType, 0, 0, 4, 6);
x += path->getBounds().width() + 10.f;
x += SkScalarCeilToScalar(path->getBounds().width() + 10.f);
}
// Draw AA and non AA paths using normal API for reference.
@ -155,18 +171,69 @@ protected:
canvas->drawPath(*path, paint);
canvas->restore();
y += path->getBounds().height() + 20.f;
y += SkScalarCeilToScalar(path->getBounds().height() + 20.f);
}
// Draw rects. We only have specialized effect code for the AA case, so don't do non-AA.
for (SkTLList<SkRect>::Iter iter(fRects, SkTLList<SkRect>::Iter::kHead_IterStart);
NULL != iter.get();
iter.next()) {
SkScalar x = 0;
GrTestTarget tt;
context->getTestTarget(&tt);
if (NULL == tt.target()) {
SkDEBUGFAIL("Couldn't get Gr test target.");
return;
}
SkRect rect = *iter.get();
rect.offset(x, y);
SkAutoTUnref<GrEffectRef> effect(GrConvexPolyEffect::CreateForAAFillRect(rect));
if (!effect) {
SkDEBUGFAIL("Couldn't create convex poly effect.");
return;
}
GrDrawState* drawState = tt.target()->drawState();
drawState->setVertexAttribs<kAttribs>(SK_ARRAY_COUNT(kAttribs));
drawState->addCoverageEffect(effect, 1);
drawState->setIdentityViewMatrix();
drawState->setRenderTarget(rt);
drawState->setColor(0xff000000);
SkPoint verts[4];
SkRect bounds = rect;
bounds.outset(5.f, 5.f);
bounds.toQuad(verts);
tt.target()->setVertexSourceToArray(verts, 4);
tt.target()->setIndexSourceToBuffer(context->getQuadIndexBuffer());
tt.target()->drawIndexed(kTriangleFan_GrPrimitiveType, 0, 0, 4, 6);
x += SkScalarCeilToScalar(rect.width() + 10.f);
// Draw AA rect using normal API for reference
canvas->save();
canvas->translate(x, y);
SkPaint paint;
paint.setAntiAlias(true);
canvas->drawRect(*iter.get(), paint);
canvas->restore();
y += SkScalarCeilToScalar(rect.height() + 20.f);
}
}
private:
SkTLList<SkPath> fPaths;
SkTLList<SkRect> fRects;
typedef GM INHERITED;
};
DEF_GM( return SkNEW(ConvexPolyEffect); )
}
#endif

View File

@ -67,7 +67,7 @@ private:
*/
#define GR_DECLARE_EFFECT_TEST \
static GrEffectTestFactory gTestFactory; \
static GrEffectRef* TestCreate(SkRandom*, \
static GrEffectRef* TestCreate(SkRandom*, \
GrContext*, \
const GrDrawTargetCaps&, \
GrTexture* dummyTextures[2])
@ -91,7 +91,7 @@ private:
// The unit test relies on static initializers. Just declare the TestCreate function so that
// its definitions will compile.
#define GR_DECLARE_EFFECT_TEST \
static GrEffectRef* TestCreate(SkRandom*, \
static GrEffectRef* TestCreate(SkRandom*, \
GrContext*, \
const GrDrawTargetCaps&, \
GrTexture* dummyTextures[2])

View File

@ -156,25 +156,37 @@ bool GrClipMaskManager::setupClipping(const GrClipData* clipDataIn,
// If there is only one clip element and it is a convex polygon we just install an effect that
// clips against the edges.
if (1 == elements.count() && SkClipStack::Element::kPath_Type == elements.tail()->getType() &&
SkRegion::kReplace_Op == elements.tail()->getOp()) {
const SkPath& path = elements.tail()->getPath();
bool isAA = GR_AA_CLIP && elements.tail()->isAA();
if (1 == elements.count() && SkRegion::kReplace_Op == elements.tail()->getOp()) {
SkAutoTUnref<GrEffectRef> effect;
if (rt->isMultisampled()) {
// A coverage effect for AA clipping won't play nicely with MSAA.
if (!isAA) {
if (SkClipStack::Element::kPath_Type == elements.tail()->getType()) {
const SkPath& path = elements.tail()->getPath();
bool isAA = GR_AA_CLIP && elements.tail()->isAA();
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(GrConvexPolyEffect::kFillNoAA_EdgeType,
path, &offset));
}
} else {
SkVector offset = { SkIntToScalar(-clipDataIn->fOrigin.fX),
SkIntToScalar(-clipDataIn->fOrigin.fY) };
effect.reset(GrConvexPolyEffect::Create(GrConvexPolyEffect::kFillNoAA_EdgeType,
path, &offset));
GrConvexPolyEffect::EdgeType type = isAA ? GrConvexPolyEffect::kFillAA_EdgeType :
GrConvexPolyEffect::kFillNoAA_EdgeType;
effect.reset(GrConvexPolyEffect::Create(type, path, &offset));
}
} else {
} else if (GR_AA_CLIP && elements.tail()->isAA() && !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.
SkASSERT(SkClipStack::Element::kRect_Type == elements.tail()->getType());
SkRect rect = elements.tail()->getRect();
SkVector offset = { SkIntToScalar(-clipDataIn->fOrigin.fX),
SkIntToScalar(-clipDataIn->fOrigin.fY) };
GrConvexPolyEffect::EdgeType type = isAA ? GrConvexPolyEffect::kFillAA_EdgeType :
GrConvexPolyEffect::kFillNoAA_EdgeType;
effect.reset(GrConvexPolyEffect::Create(type, path, &offset));
SkIntToScalar(-clipDataIn->fOrigin.fY) };
rect.offset(offset);
effect.reset(GrConvexPolyEffect::CreateForAAFillRect(rect));
// This should never fail.
SkASSERT(effect);
}
if (effect) {
are->set(fGpu->drawState());

View File

@ -14,6 +14,138 @@
#include "SkPath.h"
//////////////////////////////////////////////////////////////////////////////
class GLAARectEffect;
class AARectEffect : public GrEffect {
public:
typedef GLAARectEffect GLEffect;
const SkRect& getRect() const { return fRect; }
static const char* Name() { return "AARect"; }
static GrEffectRef* Create(const SkRect& rect) {
return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(AARectEffect, (rect))));
}
virtual void getConstantColorComponents(GrColor* color,
uint32_t* validFlags) const SK_OVERRIDE {
if (fRect.isEmpty()) {
// An empty rect will have no coverage anywhere.
*color = 0x00000000;
*validFlags = kRGBA_GrColorComponentFlags;
} else {
*validFlags = 0;
}
}
virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
private:
AARectEffect(const SkRect& rect) : fRect(rect) {
this->setWillReadFragmentPosition();
}
virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
const AARectEffect& aare = CastEffect<AARectEffect>(other);
return fRect == aare.fRect;
}
SkRect fRect;
typedef GrEffect INHERITED;
GR_DECLARE_EFFECT_TEST;
};
GR_DEFINE_EFFECT_TEST(AARectEffect);
GrEffectRef* AARectEffect::TestCreate(SkRandom* random,
GrContext*,
const GrDrawTargetCaps& caps,
GrTexture*[]) {
SkRect rect = SkRect::MakeLTRB(random->nextSScalar1(),
random->nextSScalar1(),
random->nextSScalar1(),
random->nextSScalar1());
return AARectEffect::Create(rect);
}
//////////////////////////////////////////////////////////////////////////////
class GLAARectEffect : public GrGLEffect {
public:
GLAARectEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
virtual void emitCode(GrGLShaderBuilder* builder,
const GrDrawEffect& drawEffect,
EffectKey key,
const char* outputColor,
const char* inputColor,
const TransformedCoordsArray&,
const TextureSamplerArray&) SK_OVERRIDE;
static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&) { return 0; }
virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
private:
GrGLUniformManager::UniformHandle fRectUniform;
SkRect fPrevRect;
typedef GrGLEffect INHERITED;
};
GLAARectEffect::GLAARectEffect(const GrBackendEffectFactory& factory,
const GrDrawEffect& drawEffect)
: INHERITED (factory) {
fPrevRect.fLeft = SK_ScalarNaN;
}
void GLAARectEffect::emitCode(GrGLShaderBuilder* builder,
const GrDrawEffect& drawEffect,
EffectKey key,
const char* outputColor,
const char* inputColor,
const TransformedCoordsArray&,
const TextureSamplerArray& samplers) {
const char *rectName;
fRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
kVec4f_GrSLType,
"rect",
&rectName);
const char* fragmentPos = builder->fragmentPosition();
// The rect uniform's xyzw refer to (left + 0.5, top + 0.5, right - 0.5, bottom - 0.5),
// respectively. The amount of coverage removed in x and y by the edges is computed as a pair of
// negative numbers, xSub and ySub.
builder->fsCodeAppend("\t\tfloat xSub, ySub;\n");
builder->fsCodeAppendf("\t\txSub = min(%s.x - %s.x, 0.0);\n", fragmentPos, rectName);
builder->fsCodeAppendf("\t\txSub += min(%s.z - %s.x, 0.0);\n", rectName, fragmentPos);
builder->fsCodeAppendf("\t\tySub = min(%s.y - %s.y, 0.0);\n", fragmentPos, rectName);
builder->fsCodeAppendf("\t\tySub += min(%s.w - %s.y, 0.0);\n", rectName, fragmentPos);
// Now compute coverage in x and y and multiply them to get the fraction of the pixel covered.
builder->fsCodeAppendf("\t\tfloat alpha = (1.0 + max(xSub, -1.0)) * (1.0 + max(ySub, -1.0));\n");
builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor,
(GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str());
}
void GLAARectEffect::setData(const GrGLUniformManager& uman, const GrDrawEffect& drawEffect) {
const AARectEffect& aare = drawEffect.castEffect<AARectEffect>();
const SkRect& rect = aare.getRect();
if (rect != fPrevRect) {
uman.set4f(fRectUniform, rect.fLeft + 0.5f, rect.fTop + 0.5f,
rect.fRight - 0.5f, rect.fBottom - 0.5f);
fPrevRect = rect;
}
}
const GrBackendEffectFactory& AARectEffect::getFactory() const {
return GrTBackendEffectFactory<AARectEffect>::getInstance();
}
//////////////////////////////////////////////////////////////////////////////
class GrGLConvexPolyEffect : public GrGLEffect {
public:
GrGLConvexPolyEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
@ -146,6 +278,10 @@ GrEffectRef* GrConvexPolyEffect::Create(EdgeType type, const SkPath& path, const
return Create(type, n, edges);
}
GrEffectRef* GrConvexPolyEffect::CreateForAAFillRect(const SkRect& rect) {
return AARectEffect::Create(rect);
}
GrConvexPolyEffect::~GrConvexPolyEffect() {}
void GrConvexPolyEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {

View File

@ -62,6 +62,11 @@ public:
*/
static GrEffectRef* Create(EdgeType, const SkPath&, const SkVector* offset= NULL);
/**
* Creates an effect that fills inside the rect with AA edges..
*/
static GrEffectRef* CreateForAAFillRect(const SkRect&);
virtual ~GrConvexPolyEffect();
static const char* Name() { return "ConvexPoly"; }