diff options
Diffstat (limited to 'src/gpu')
-rw-r--r-- | src/gpu/GrAARectRenderer.cpp | 215 | ||||
-rw-r--r-- | src/gpu/GrContext.cpp | 58 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.cpp | 11 |
3 files changed, 269 insertions, 15 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, diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index 1b62062cc1..9755ecfde2 100644 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -682,7 +682,7 @@ static bool isIRect(const GrRect& r) { static bool apply_aa_to_rect(GrDrawTarget* target, const GrRect& rect, - SkScalar width, + SkScalar strokeWidth, const SkMatrix* matrix, SkMatrix* combinedMatrix, GrRect* devRect, @@ -711,29 +711,54 @@ static bool apply_aa_to_rect(GrDrawTarget* target, return false; } - if (0 == width && target->willUseHWAALines()) { + if (0 == strokeWidth && target->willUseHWAALines()) { return false; } - if (!drawState.getViewMatrix().preservesAxisAlignment()) { - return false; - } +#ifdef SHADER_AA_FILL_RECT + if (strokeWidth >= 0) { +#endif + if (!drawState.getViewMatrix().preservesAxisAlignment()) { + return false; + } - if (NULL != matrix && - !matrix->preservesAxisAlignment()) { - return false; + if (NULL != matrix && !matrix->preservesAxisAlignment()) { + return false; + } +#ifdef SHADER_AA_FILL_RECT + } else { + if (!drawState.getViewMatrix().preservesAxisAlignment() && + !drawState.getViewMatrix().preservesRightAngles()) { + return false; + } + + if (NULL != matrix && !matrix->preservesRightAngles()) { + return false; + } } +#endif *combinedMatrix = drawState.getViewMatrix(); if (NULL != matrix) { combinedMatrix->preConcat(*matrix); - GrAssert(combinedMatrix->preservesAxisAlignment()); + +#if GR_DEBUG +#ifdef SHADER_AA_FILL_RECT + if (strokeWidth >= 0) { +#endif + GrAssert(combinedMatrix->preservesAxisAlignment()); +#ifdef SHADER_AA_FILL_RECT + } else { + GrAssert(combinedMatrix->preservesRightAngles()); + } +#endif +#endif } combinedMatrix->mapRect(devRect, rect); devRect->sort(); - if (width < 0) { + if (strokeWidth < 0) { return !isIRect(*devRect); } else { return true; @@ -757,7 +782,6 @@ void GrContext::drawRect(const GrPaint& paint, bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix, &combinedMatrix, &devRect, &useVertexCoverage); - if (doAA) { GrDrawState::AutoDeviceCoordDraw adcd(target->drawState()); if (!adcd.succeeded()) { @@ -773,10 +797,17 @@ void GrContext::drawRect(const GrPaint& paint, strokeSize.set(SK_Scalar1, SK_Scalar1); } fAARectRenderer->strokeAARect(this->getGpu(), target, devRect, - strokeSize, useVertexCoverage); + strokeSize, useVertexCoverage); } else { + // filled AA rect +#ifdef SHADER_AA_FILL_RECT + fAARectRenderer->shaderFillAARect(this->getGpu(), target, + rect, combinedMatrix, devRect, + useVertexCoverage); +#else fAARectRenderer->fillAARect(this->getGpu(), target, - devRect, useVertexCoverage); + devRect, useVertexCoverage); +#endif } return; } @@ -822,6 +853,7 @@ void GrContext::drawRect(const GrPaint& paint, target->drawNonIndexed(primType, 0, vertCount); } else { + // filled BW rect #if GR_STATIC_RECT_VB const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer(); if (NULL == sqVB) { diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index c1364afe02..356fcac243 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -671,9 +671,16 @@ void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect, if (paint.getMaskFilter() || paint.getPathEffect()) { usePath = true; } - // until we aa rotated rects... if (!usePath && paint.isAntiAlias() && !fContext->getMatrix().rectStaysRect()) { - usePath = true; +#ifdef SHADER_AA_FILL_RECT + if (doStroke) { +#endif + usePath = true; +#ifdef SHADER_AA_FILL_RECT + } else { + usePath = !fContext->getMatrix().preservesRightAngles(); + } +#endif } // small miter limit means right angles show bevel... if (SkPaint::kMiter_Join == paint.getStrokeJoin() && |