Index: src/gpu/GrAARectRenderer.cpp |
=================================================================== |
--- src/gpu/GrAARectRenderer.cpp (revision 8570) |
+++ src/gpu/GrAARectRenderer.cpp (working copy) |
@@ -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 @@ |
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, |