diff options
Diffstat (limited to 'src/gpu/GrAARectRenderer.cpp')
-rw-r--r-- | src/gpu/GrAARectRenderer.cpp | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/src/gpu/GrAARectRenderer.cpp b/src/gpu/GrAARectRenderer.cpp index 6f074e6524..37df53ae70 100644 --- a/src/gpu/GrAARectRenderer.cpp +++ b/src/gpu/GrAARectRenderer.cpp @@ -8,9 +8,138 @@ #include "GrAARectRenderer.h" #include "GrRefCnt.h" #include "GrGpu.h" +#include "gl/GrGLEffect.h" +#include "GrTBackendEffectFactory.h" SK_DEFINE_INST_COUNT(GrAARectRenderer) +class GrGLRectEffect; + +/** + * The output of this effect is a modulation of the input color and coverage + * for an arbitrarily oriented rect. The rect is specified as: + * Center of the rect + * Unit vector point down the height of the rect + * Half width + 0.5 + * Half height + 0.5 + * The center and vector are stored in a vec4 varying ("RectEdge") with the + * center in the xy components and the vector in the zw components. + * The munged width and height are stored in a vec2 varying ("WidthHeight") + * with the width in x and the height in y. + */ +class GrRectEffect : public GrEffect { +public: + static GrEffectRef* Create() { + static SkAutoTUnref<GrEffectRef> gRectEffectRef( + CreateEffectRef(AutoEffectUnref(SkNEW(GrRectEffect)))); + gRectEffectRef.get()->ref(); + return gRectEffectRef; + } + + virtual ~GrRectEffect() {} + + static const char* Name() { return "RectEdge"; } + + virtual void getConstantColorComponents(GrColor* color, + uint32_t* validFlags) const SK_OVERRIDE { + *validFlags = 0; + } + + virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { + return GrTBackendEffectFactory<GrRectEffect>::getInstance(); + } + + class GLEffect : public GrGLEffect { + public: + GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) + : INHERITED (factory) {} + + virtual void emitCode(GrGLShaderBuilder* builder, + const GrDrawEffect& drawEffect, + EffectKey key, + const char* outputColor, + const char* inputColor, + const TextureSamplerArray& samplers) SK_OVERRIDE { + // setup the varying for the center point and the unit vector + // that points down the height of the rect + const char *vsRectEdgeName, *fsRectEdgeName; + builder->addVarying(kVec4f_GrSLType, "RectEdge", + &vsRectEdgeName, &fsRectEdgeName); + const SkString* attr0Name = + builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]); + builder->vsCodeAppendf("\t%s = %s;\n", vsRectEdgeName, attr0Name->c_str()); + + // setup the varying for width/2+.5 and height/2+.5 + const char *vsWidthHeightName, *fsWidthHeightName; + builder->addVarying(kVec2f_GrSLType, "WidthHeight", + &vsWidthHeightName, &fsWidthHeightName); + const SkString* attr1Name = + builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]); + builder->vsCodeAppendf("\t%s = %s;\n", vsWidthHeightName, attr1Name->c_str()); + + // TODO: compute these scale factors in the VS + // These scale factors adjust the coverage for < 1 pixel wide/high rects + builder->fsCodeAppendf("\tfloat wScale = max(1.0, 2.0/(0.5+%s.x));\n", + fsWidthHeightName); + builder->fsCodeAppendf("\tfloat hScale = max(1.0, 2.0/(0.5+%s.y));\n", + fsWidthHeightName); + + // Compute the coverage for the rect's width + builder->fsCodeAppendf("\tvec2 offset = %s.xy - %s.xy;\n", + builder->fragmentPosition(), fsRectEdgeName); + builder->fsCodeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n", + fsRectEdgeName, fsRectEdgeName); + builder->fsCodeAppendf("\tfloat coverage = clamp(wScale*(%s.x-perpDot), 0.0, 1.0);\n", + fsWidthHeightName); + + // Compute the coverage for the rect's height and merge with the width + builder->fsCodeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n", + fsRectEdgeName); + builder->fsCodeAppendf( + "\tcoverage = min(coverage, clamp(hScale*(%s.y-perpDot), 0.0, 1.0));\n", + fsWidthHeightName); + + SkString modulate; + GrGLSLModulate4f(&modulate, inputColor, "coverage"); + builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str()); + } + + static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) { + return 0; + } + + virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {} + + private: + typedef GrGLEffect INHERITED; + }; + + +private: + GrRectEffect::GrRectEffect() : GrEffect() { + this->addVertexAttrib(kVec4f_GrSLType); + this->addVertexAttrib(kVec2f_GrSLType); + } + + virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; } + + GR_DECLARE_EFFECT_TEST; + + typedef GrEffect INHERITED; +}; + + +GR_DEFINE_EFFECT_TEST(GrRectEffect); + +GrEffectRef* GrRectEffect::TestCreate(SkMWCRandom* random, + GrContext* context, + const GrDrawTargetCaps&, + GrTexture* textures[]) { + return GrRectEffect::Create(); +} + +/////////////////////////////////////////////////////////////////////////////// + namespace { static void aa_rect_attributes(bool useCoverage, const GrVertexAttrib** attribs, int* count) { @@ -181,6 +310,92 @@ void GrAARectRenderer::fillAARect(GrGpu* gpu, target->resetIndexSource(); } +struct RectVertex { + GrPoint fPos; + GrPoint fCenter; + GrPoint fDir; + GrPoint fWidthHeight; +}; + + +void GrAARectRenderer::shaderFillAARect(GrGpu* gpu, + GrDrawTarget* target, + const GrRect& rect, + const SkMatrix& combinedMatrix, + const GrRect& devRect, + bool useVertexCoverage) { + GrDrawState* drawState = target->drawState(); + + SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY()); + combinedMatrix.mapPoints(¢er, 1); + + // compute transformed (0, 1) vector + SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }; + dir.normalize(); + + // compute transformed (width, 0) and (0, height) vectors + SkVector vec[2] = { + { combinedMatrix[SkMatrix::kMScaleX] * rect.width(), + combinedMatrix[SkMatrix::kMSkewY] * rect.width() }, + { combinedMatrix[SkMatrix::kMSkewX] * rect.height(), + combinedMatrix[SkMatrix::kMScaleY] * rect.height() } + }; + + SkScalar newWidth = vec[0].length() / 2.0f + 0.5f; + SkScalar newHeight = vec[1].length() / 2.0f + 0.5f; + + static const GrVertexAttrib kVertexAttribs[] = { + { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding }, + { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding }, + { kVec2f_GrVertexAttribType, 3*sizeof(GrPoint), kEffect_GrVertexAttribBinding } + }; + drawState->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs)); + GrAssert(sizeof(RectVertex) == drawState->getVertexSize()); + + GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0); + if (!geo.succeeded()) { + GrPrintf("Failed to get space for vertices!\n"); + return; + } + + RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices()); + + enum { + // the edge effects share this stage with glyph rendering + // (kGlyphMaskStage in GrTextContext) && SW path rendering + // (kPathMaskStage in GrSWMaskHelper) + kEdgeEffectStage = GrPaint::kTotalStages, + }; + + GrEffectRef* effect = GrRectEffect::Create(); + static const int kRectAttrIndex = 1; + static const int kWidthIndex = 2; + drawState->setEffect(kEdgeEffectStage, effect, kRectAttrIndex, kWidthIndex)->unref(); + + for (int i = 0; i < 4; ++i) { + verts[i].fCenter = center; + verts[i].fDir = dir; + verts[i].fWidthHeight.fX = newWidth; + verts[i].fWidthHeight.fY = newHeight; + } + + SkRect devBounds = { + devRect.fLeft - SK_ScalarHalf, + devRect.fTop - SK_ScalarHalf, + devRect.fRight + SK_ScalarHalf, + devRect.fBottom + SK_ScalarHalf + }; + + verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop); + verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom); + verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom); + verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop); + + target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer()); + target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6); + target->resetIndexSource(); +} + void GrAARectRenderer::strokeAARect(GrGpu* gpu, GrDrawTarget* target, const GrRect& devRect, |