aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gyp/gpu.gypi2
-rw-r--r--src/gpu/GrAAConvexPathRenderer.cpp22
-rw-r--r--src/gpu/GrAAHairLinePathRenderer.cpp27
-rw-r--r--src/gpu/GrDrawState.cpp31
-rw-r--r--src/gpu/GrDrawState.h58
-rw-r--r--src/gpu/effects/GrEdgeEffect.cpp138
-rw-r--r--src/gpu/effects/GrEdgeEffect.h85
-rw-r--r--src/gpu/gl/GrGLProgram.cpp93
-rw-r--r--src/gpu/gl/GrGLProgram.h8
-rw-r--r--tests/GLProgramsTest.cpp19
10 files changed, 281 insertions, 202 deletions
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi
index 537497647a..c28045d95b 100644
--- a/gyp/gpu.gypi
+++ b/gyp/gpu.gypi
@@ -131,6 +131,8 @@
'<(skia_src_path)/gpu/effects/GrConfigConversionEffect.h',
'<(skia_src_path)/gpu/effects/GrConvolutionEffect.cpp',
'<(skia_src_path)/gpu/effects/GrConvolutionEffect.h',
+ '<(skia_src_path)/gpu/effects/GrEdgeEffect.cpp',
+ '<(skia_src_path)/gpu/effects/GrEdgeEffect.h',
'<(skia_src_path)/gpu/effects/GrEllipseEdgeEffect.cpp',
'<(skia_src_path)/gpu/effects/GrEllipseEdgeEffect.h',
'<(skia_src_path)/gpu/effects/GrSimpleTextureEffect.cpp',
diff --git a/src/gpu/GrAAConvexPathRenderer.cpp b/src/gpu/GrAAConvexPathRenderer.cpp
index cff6324867..9f24190889 100644
--- a/src/gpu/GrAAConvexPathRenderer.cpp
+++ b/src/gpu/GrAAConvexPathRenderer.cpp
@@ -16,6 +16,8 @@
#include "SkStrokeRec.h"
#include "SkTrace.h"
+#include "effects/GrEdgeEffect.h"
+
GrAAConvexPathRenderer::GrAAConvexPathRenderer() {
}
@@ -446,6 +448,8 @@ bool GrAAConvexPathRenderer::onDrawPath(const SkPath& origPath,
if (path->isEmpty()) {
return true;
}
+
+ GrDrawTarget::AutoStateRestore asr(target, GrDrawTarget::kPreserve_ASRInit);
GrDrawState* drawState = target->drawState();
GrDrawState::AutoDeviceCoordDraw adcd(drawState);
@@ -484,12 +488,21 @@ bool GrAAConvexPathRenderer::onDrawPath(const SkPath& origPath,
{kVec2f_GrVertexAttribType, 0},
{kVec4f_GrVertexAttribType, sizeof(GrPoint)}
};
- static const GrAttribBindings bindings = GrDrawState::kEdge_AttribBindingsBit;
drawState->setVertexAttribs(kAttribs, SK_ARRAY_COUNT(kAttribs));
drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0);
- drawState->setAttribIndex(GrDrawState::kEdge_AttribIndex, 1);
- drawState->setAttribBindings(bindings);
+ drawState->setAttribBindings(GrDrawState::kDefault_AttribBindings);
+
+ enum {
+ // the edge effects share this stage with glyph rendering
+ // (kGlyphMaskStage in GrTextContext) && SW path rendering
+ // (kPathMaskStage in GrSWMaskHelper)
+ kEdgeEffectStage = GrPaint::kTotalStages,
+ };
+ static const int kEdgeAttrIndex = 1;
+ GrEffectRef* quadEffect = GrEdgeEffect::Create(GrEdgeEffect::kQuad_EdgeType);
+ drawState->setEffect(kEdgeEffectStage, quadEffect, kEdgeAttrIndex)->unref();
+
GrDrawTarget::AutoReleaseGeometry arg(target, vCount, iCount);
if (!arg.succeeded()) {
return false;
@@ -500,14 +513,11 @@ bool GrAAConvexPathRenderer::onDrawPath(const SkPath& origPath,
create_vertices(segments, fanPt, verts, idxs);
- GrDrawState::VertexEdgeType oldEdgeType = drawState->getVertexEdgeType();
- drawState->setVertexEdgeType(GrDrawState::kQuad_EdgeType);
target->drawIndexed(kTriangles_GrPrimitiveType,
0, // start vertex
0, // start index
vCount,
iCount);
- drawState->setVertexEdgeType(oldEdgeType);
return true;
}
diff --git a/src/gpu/GrAAHairLinePathRenderer.cpp b/src/gpu/GrAAHairLinePathRenderer.cpp
index 80304f822e..079c826e4e 100644
--- a/src/gpu/GrAAHairLinePathRenderer.cpp
+++ b/src/gpu/GrAAHairLinePathRenderer.cpp
@@ -18,6 +18,8 @@
#include "SkStroke.h"
#include "SkTemplates.h"
+#include "effects/GrEdgeEffect.h"
+
namespace {
// quadratics are rendered as 5-sided polys in order to bound the
// AA stroke around the center-curve. See comments in push_quad_index_buffer and
@@ -508,7 +510,6 @@ bool GrAAHairLinePathRenderer::createGeom(
{kVec2f_GrVertexAttribType, 0},
{kVec4f_GrVertexAttribType, sizeof(GrPoint)}
};
- static const GrAttribBindings kBindings = GrDrawState::kEdge_AttribBindingsBit;
SkMatrix viewM = drawState->getViewMatrix();
PREALLOC_PTARRAY(128) lines;
@@ -522,8 +523,7 @@ bool GrAAHairLinePathRenderer::createGeom(
target->drawState()->setVertexAttribs(kAttribs, SK_ARRAY_COUNT(kAttribs));
target->drawState()->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0);
- target->drawState()->setAttribIndex(GrDrawState::kEdge_AttribIndex, 1);
- target->drawState()->setAttribBindings(kBindings);
+ target->drawState()->setAttribBindings(GrDrawState::kDefault_AttribBindings);
GrAssert(sizeof(Vertex) == target->getDrawState().getVertexSize());
if (!arg->set(target, vertCnt, 0)) {
@@ -589,8 +589,10 @@ bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path,
return false;
}
- GrDrawState::AutoDeviceCoordDraw adcd;
+ GrDrawTarget::AutoStateRestore asr(target, GrDrawTarget::kPreserve_ASRInit);
GrDrawState* drawState = target->drawState();
+
+ GrDrawState::AutoDeviceCoordDraw adcd;
// createGeom transforms the geometry to device space when the matrix does not have
// perspective.
if (!drawState->getViewMatrix().hasPerspective()) {
@@ -603,12 +605,21 @@ bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path,
// TODO: See whether rendering lines as degenerate quads improves perf
// when we have a mix
- GrDrawState::VertexEdgeType oldEdgeType = drawState->getVertexEdgeType();
+ enum {
+ // the edge effects share this stage with glyph rendering
+ // (kGlyphMaskStage in GrTextContext) && SW path rendering
+ // (kPathMaskStage in GrSWMaskHelper)
+ kEdgeEffectStage = GrPaint::kTotalStages,
+ };
+ static const int kEdgeAttrIndex = 1;
+ GrEffectRef* hairLineEffect = GrEdgeEffect::Create(GrEdgeEffect::kHairLine_EdgeType);
+ GrEffectRef* hairQuadEffect = GrEdgeEffect::Create(GrEdgeEffect::kHairQuad_EdgeType);
+
target->setIndexSourceToBuffer(fLinesIndexBuffer);
int lines = 0;
int nBufLines = fLinesIndexBuffer->maxQuads();
- drawState->setVertexEdgeType(GrDrawState::kHairLine_EdgeType);
+ drawState->setEffect(kEdgeEffectStage, hairLineEffect, kEdgeAttrIndex)->unref();
while (lines < lineCnt) {
int n = GrMin(lineCnt - lines, nBufLines);
target->drawIndexed(kTriangles_GrPrimitiveType,
@@ -621,7 +632,7 @@ bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path,
target->setIndexSourceToBuffer(fQuadsIndexBuffer);
int quads = 0;
- drawState->setVertexEdgeType(GrDrawState::kHairQuad_EdgeType);
+ drawState->setEffect(kEdgeEffectStage, hairQuadEffect, kEdgeAttrIndex)->unref();
while (quads < quadCnt) {
int n = GrMin(quadCnt - quads, kNumQuadsInIdxBuffer);
target->drawIndexed(kTriangles_GrPrimitiveType,
@@ -631,6 +642,6 @@ bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path,
kIdxsPerQuad*n); // iCount
quads += n;
}
- drawState->setVertexEdgeType(oldEdgeType);
+
return true;
}
diff --git a/src/gpu/GrDrawState.cpp b/src/gpu/GrDrawState.cpp
index 79829357ba..e10899958b 100644
--- a/src/gpu/GrDrawState.cpp
+++ b/src/gpu/GrDrawState.cpp
@@ -59,7 +59,7 @@ static size_t vertex_size(const GrVertexAttrib* attribs, int count) {
#if GR_DEBUG
uint32_t overlapCheck = 0;
#endif
- GrAssert(count <= GrDrawState::kAttribIndexCount);
+ GrAssert(count <= GrDrawState::kVertexAttribCnt);
size_t size = 0;
for (int index = 0; index < count; ++index) {
size_t attribSize = GrDrawState::kVertexAttribSizes[attribs[index].fType];
@@ -83,14 +83,13 @@ const GrAttribBindings GrDrawState::kAttribIndexMasks[kAttribIndexCount] = {
0, // position is not reflected in the bindings
kColor_AttribBindingsBit,
kCoverage_AttribBindingsBit,
- kEdge_AttribBindingsBit,
kLocalCoords_AttribBindingsBit,
};
////////////////////////////////////////////////////////////////////////////////
void GrDrawState::setVertexAttribs(const GrVertexAttrib* attribs, int count) {
- GrAssert(count <= GrDrawState::kAttribIndexCount);
+ GrAssert(count <= GrDrawState::kVertexAttribCnt);
fVertexAttribs.reset();
for (int index = 0; index < count; ++index) {
fVertexAttribs.push_back(attribs[index]);
@@ -140,18 +139,16 @@ bool GrDrawState::validateVertexAttribs() const {
attributeTypes[attributeIndex] = kBuiltInAttributeType;
}
}
- for (int j = kEdge_AttribIndex; j < kAttribIndexCount; ++j) {
- if (fCommon.fAttribBindings & kAttribIndexMasks[j]) {
- int attributeIndex = fAttribIndices[j];
- if (attributeIndex >= kVertexAttribCnt) {
- return false;
- }
- // they should not be shared at all
- if (attributeTypes[attributeIndex] != -1) {
- return false;
- }
- attributeTypes[attributeIndex] = kBuiltInAttributeType;
+ if (fCommon.fAttribBindings & kAttribIndexMasks[kLocalCoords_AttribIndex]) {
+ int attributeIndex = fAttribIndices[kLocalCoords_AttribIndex];
+ if (attributeIndex >= kVertexAttribCnt) {
+ return false;
+ }
+ // they should not be shared at all
+ if (attributeTypes[attributeIndex] != -1) {
+ return false;
}
+ attributeTypes[attributeIndex] = kBuiltInAttributeType;
}
// now those set by effects
@@ -371,12 +368,10 @@ GrDrawState::BlendOptFlags GrDrawState::getBlendOpts(bool forceCoverage,
}
}
- // check for coverage due to constant coverage, per-vertex coverage,
- // edge aa or coverage stage
+ // check for coverage due to constant coverage, per-vertex coverage, or coverage stage
bool hasCoverage = forceCoverage ||
0xffffffff != this->getCoverage() ||
- (bindings & GrDrawState::kCoverage_AttribBindingsBit) ||
- (bindings & GrDrawState::kEdge_AttribBindingsBit);
+ (bindings & GrDrawState::kCoverage_AttribBindingsBit);
for (int s = this->getFirstCoverageStage();
!hasCoverage && s < GrDrawState::kNumStages;
++s) {
diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h
index ffa7b093bb..fed89dbefc 100644
--- a/src/gpu/GrDrawState.h
+++ b/src/gpu/GrDrawState.h
@@ -76,9 +76,7 @@ public:
*
* The input color to the first enabled color-stage is either the constant color or interpolated
* per-vertex colors, depending upon GrAttribBindings. The input to the first coverage stage is
- * either a constant coverage (usually full-coverage), interpolated per-vertex coverage, or
- * edge-AA computed coverage. (This latter is going away as soon as it can be rewritten as a
- * GrEffect).
+ * either a constant coverage (usually full-coverage) or interpolated per-vertex coverage.
*
* See the documentation of kCoverageDrawing_StateBit for information about disabling the
* the color / coverage distinction.
@@ -125,7 +123,6 @@ public:
fCommon.fDstBlend = kZero_GrBlendCoeff;
fCommon.fBlendConstant = 0x0;
fCommon.fFlagBits = 0x0;
- fCommon.fVertexEdgeType = kHairLine_EdgeType;
fCommon.fStencilSettings.setDisabled();
fCommon.fFirstCoverageStage = kNumStages;
fCommon.fCoverage = 0xffffffff;
@@ -273,10 +270,6 @@ public:
/* program uses coverage (GrColor)
*/
kCoverage_AttribBindingsBit = 0x4,
- /* program uses edge data. Distance to the edge is used to
- * compute a coverage. See GrDrawState::setVertexEdgeType().
- */
- kEdge_AttribBindingsBit = 0x8,
// for below assert
kDummyAttribBindingsBit,
kHighAttribBindingsBit = kDummyAttribBindingsBit - 1
@@ -332,7 +325,6 @@ public:
kPosition_AttribIndex = 0,
kColor_AttribIndex,
kCoverage_AttribIndex,
- kEdge_AttribIndex,
kLocalCoords_AttribIndex,
kLast_AttribIndex = kLocalCoords_AttribIndex
@@ -947,52 +939,6 @@ public:
/// @}
///////////////////////////////////////////////////////////////////////////
- // @name Edge AA
- // Edge equations can be specified to perform anti-aliasing. Because the
- // edges are specified as per-vertex data, vertices that are shared by
- // multiple edges must be split.
- //
- ////
-
- /**
- * When specifying edges as vertex data this enum specifies what type of
- * edges are in use. The edges are always 4 SkScalars in memory, even when
- * the edge type requires fewer than 4.
- *
- * TODO: Fix the fact that HairLine and Circle edge types use y-down coords.
- * (either adjust in VS or use origin_upper_left in GLSL)
- */
- enum VertexEdgeType {
- /* 1-pixel wide line
- 2D implicit line eq (a*x + b*y +c = 0). 4th component unused */
- kHairLine_EdgeType,
- /* Quadratic specified by u^2-v canonical coords (only 2
- components used). Coverage based on signed distance with negative
- being inside, positive outside. Edge specified in window space
- (y-down) */
- kQuad_EdgeType,
- /* Same as above but for hairline quadratics. Uses unsigned distance.
- Coverage is min(0, 1-distance). */
- kHairQuad_EdgeType,
-
- kVertexEdgeTypeCnt
- };
-
- /**
- * Determines the interpretation per-vertex edge data when the
- * kEdge_AttribBindingsBit is set (see GrDrawTarget). When per-vertex edges
- * are not specified the value of this setting has no effect.
- */
- void setVertexEdgeType(VertexEdgeType type) {
- GrAssert(type >=0 && type < kVertexEdgeTypeCnt);
- fCommon.fVertexEdgeType = type;
- }
-
- VertexEdgeType getVertexEdgeType() const { return fCommon.fVertexEdgeType; }
-
- /// @}
-
- ///////////////////////////////////////////////////////////////////////////
/// @name State Flags
////
@@ -1188,7 +1134,6 @@ private:
GrBlendCoeff fDstBlend;
GrColor fBlendConstant;
uint32_t fFlagBits;
- VertexEdgeType fVertexEdgeType;
GrStencilSettings fStencilSettings;
int fFirstCoverageStage;
GrColor fCoverage;
@@ -1203,7 +1148,6 @@ private:
fDstBlend == other.fDstBlend &&
fBlendConstant == other.fBlendConstant &&
fFlagBits == other.fFlagBits &&
- fVertexEdgeType == other.fVertexEdgeType &&
fStencilSettings == other.fStencilSettings &&
fFirstCoverageStage == other.fFirstCoverageStage &&
fCoverage == other.fCoverage &&
diff --git a/src/gpu/effects/GrEdgeEffect.cpp b/src/gpu/effects/GrEdgeEffect.cpp
new file mode 100644
index 0000000000..f02fa35ae0
--- /dev/null
+++ b/src/gpu/effects/GrEdgeEffect.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrEdgeEffect.h"
+#include "gl/GrGLEffect.h"
+#include "gl/GrGLSL.h"
+#include "GrTBackendEffectFactory.h"
+
+class GrGLEdgeEffect : public GrGLEffect {
+public:
+ GrGLEdgeEffect(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 {
+ const GrEdgeEffect& edgeEffect = drawEffect.castEffect<GrEdgeEffect>();
+ GrEdgeEffect::EdgeType type = edgeEffect.edgeType();
+
+ const char *vsName, *fsName;
+ const SkString* attrName =
+ builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
+ builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n");
+
+ switch (type) {
+ case GrEdgeEffect::kHairLine_EdgeType:
+ builder->addVarying(kVec4f_GrSLType, "HairEdge", &vsName, &fsName);
+
+ builder->fsCodeAppendf("\t\tedgeAlpha = abs(dot(vec3(%s.xy,1), %s.xyz));\n",
+ builder->fragmentPosition(), fsName);
+ builder->fsCodeAppendf("\t\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
+ break;
+ case GrEdgeEffect::kQuad_EdgeType:
+ GrAssert(builder->ctxInfo().caps()->shaderDerivativeSupport());
+ builder->addVarying(kVec4f_GrSLType, "QuadEdge", &vsName, &fsName);
+
+ // keep the derivative instructions outside the conditional
+ builder->fsCodeAppendf("\t\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
+ builder->fsCodeAppendf("\t\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
+ builder->fsCodeAppendf("\t\tif (%s.z > 0.0 && %s.w > 0.0) {\n", fsName, fsName);
+ // today we know z and w are in device space. We could use derivatives
+ builder->fsCodeAppendf("\t\t\tedgeAlpha = min(min(%s.z, %s.w) + 0.5, 1.0);\n", fsName,
+ fsName);
+ builder->fsCodeAppendf ("\t\t} else {\n");
+ builder->fsCodeAppendf("\t\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
+ "\t\t\t 2.0*%s.x*duvdy.x - duvdy.y);\n",
+ fsName, fsName);
+ builder->fsCodeAppendf("\t\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName,
+ fsName);
+ builder->fsCodeAppendf("\t\t\tedgeAlpha = "
+ "clamp(0.5 - edgeAlpha / length(gF), 0.0, 1.0);\n\t\t}\n");
+ if (kES2_GrGLBinding == builder->ctxInfo().binding()) {
+ builder->fHeader.append("#extension GL_OES_standard_derivatives: enable\n");
+ }
+ break;
+ case GrEdgeEffect::kHairQuad_EdgeType:
+ GrAssert(builder->ctxInfo().caps()->shaderDerivativeSupport());
+ builder->addVarying(kVec4f_GrSLType, "HairQuadEdge", &vsName, &fsName);
+
+ builder->fsCodeAppendf("\t\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
+ builder->fsCodeAppendf("\t\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
+ builder->fsCodeAppendf("\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
+ "\t\t 2.0*%s.x*duvdy.x - duvdy.y);\n",
+ fsName, fsName);
+ builder->fsCodeAppendf("\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName,
+ fsName);
+ builder->fsCodeAppend("\t\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / dot(gF, gF));\n");
+ builder->fsCodeAppend("\t\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
+ if (kES2_GrGLBinding == builder->ctxInfo().binding()) {
+ builder->fHeader.append("#extension GL_OES_standard_derivatives: enable\n");
+ }
+ break;
+ };
+
+ SkString modulate;
+ GrGLSLModulate4f(&modulate, inputColor, "edgeAlpha");
+ builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
+
+ builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str());
+ }
+
+ static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
+ const GrEdgeEffect& QuadEffect = drawEffect.castEffect<GrEdgeEffect>();
+
+ return QuadEffect.edgeType();
+ }
+
+ virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {
+ }
+
+private:
+ typedef GrGLEffect INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrEdgeEffect::GrEdgeEffect(EdgeType edgeType) : GrEffect() {
+ if (edgeType == kQuad_EdgeType) {
+ this->addVertexAttrib(kVec4f_GrSLType);
+ } else {
+ this->addVertexAttrib(kVec4f_GrSLType); // TODO: use different vec sizes for differnt edge
+ // types.
+ }
+ fEdgeType = edgeType;
+}
+
+void GrEdgeEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
+ *validFlags = 0;
+}
+
+const GrBackendEffectFactory& GrEdgeEffect::getFactory() const {
+ return GrTBackendEffectFactory<GrEdgeEffect>::getInstance();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+GR_DEFINE_EFFECT_TEST(GrEdgeEffect);
+
+GrEffectRef* GrEdgeEffect::TestCreate(SkMWCRandom* random,
+ GrContext*,
+ const GrDrawTargetCaps& caps,
+ GrTexture*[]) {
+ // Only kHairLine works without derivative instructions.
+ EdgeType edgeType;
+ if (caps.shaderDerivativeSupport()) {
+ edgeType = static_cast<EdgeType>(random->nextULessThan(kEdgeTypeCount));
+ } else {
+ edgeType = kHairLine_EdgeType;
+ }
+ return GrEdgeEffect::Create(edgeType);
+}
diff --git a/src/gpu/effects/GrEdgeEffect.h b/src/gpu/effects/GrEdgeEffect.h
new file mode 100644
index 0000000000..c6238a2e09
--- /dev/null
+++ b/src/gpu/effects/GrEdgeEffect.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrEdgeEffect_DEFINED
+#define GrEdgeEffect_DEFINED
+
+#include "GrEffect.h"
+
+class GrGLEdgeEffect;
+
+/**
+ * The output of this effect is one of three different edge types: hairlines, quads,
+ * and hairline quads.
+ */
+
+class GrEdgeEffect : public GrEffect {
+public:
+ enum EdgeType {
+ /* 1-pixel wide line
+ 2D implicit device coord line eq (a*x + b*y +c = 0). 4th component unused. */
+ kHairLine_EdgeType = 0,
+ /* Quadratic specified by 0=u^2-v canonical coords. u and v are the first
+ two components of the vertex attribute. Coverage is based on signed
+ distance with negative being inside, positive outside. The edge is specified in
+ window space (y-down). If either the third or fourth component of the interpolated
+ vertex coord is > 0 then the pixel is considered outside the edge. This is used to
+ attempt to trim to a portion of the infinite quad. Requires shader derivative
+ instruction support. */
+ kQuad_EdgeType,
+ /* Similar to above but for hairline quadratics. Uses unsigned distance.
+ Coverage is min(0, 1-distance). 3rd & 4th component unused. Requires
+ shader derivative instruction support. */
+ kHairQuad_EdgeType,
+
+ kLast_EdgeType = kHairQuad_EdgeType
+ };
+ static const int kEdgeTypeCount = kLast_EdgeType + 1;
+
+ static GrEffectRef* Create(EdgeType type) {
+ // we go through this so we only have one copy of each effect
+ static GrEffectRef* gEdgeEffectRef[kEdgeTypeCount] = {
+ CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(GrEdgeEffect, (kHairLine_EdgeType)))),
+ CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(GrEdgeEffect, (kQuad_EdgeType)))),
+ CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(GrEdgeEffect, (kHairQuad_EdgeType)))),
+ };
+ static SkAutoTUnref<GrEffectRef> gUnref0(gEdgeEffectRef[0]);
+ static SkAutoTUnref<GrEffectRef> gUnref1(gEdgeEffectRef[1]);
+ static SkAutoTUnref<GrEffectRef> gUnref2(gEdgeEffectRef[2]);
+
+ gEdgeEffectRef[type]->ref();
+ return gEdgeEffectRef[type];
+ }
+
+ virtual ~GrEdgeEffect() {}
+
+ static const char* Name() { return "Edge"; }
+
+ virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
+
+ typedef GrGLEdgeEffect GLEffect;
+
+ virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
+
+ EdgeType edgeType() const { return fEdgeType; }
+
+private:
+ GrEdgeEffect(EdgeType edgeType);
+
+ virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
+ const GrEdgeEffect& qee = CastEffect<GrEdgeEffect>(other);
+ return qee.fEdgeType == fEdgeType;
+ }
+
+ EdgeType fEdgeType;
+
+ GR_DECLARE_EFFECT_TEST;
+
+ typedef GrEffect INHERITED;
+};
+
+#endif
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index 333146868b..fc80a78939 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -87,8 +87,7 @@ void GrGLProgram::BuildDesc(const GrDrawState& drawState,
// no reason to do edge aa or look at per-vertex coverage if coverage is ignored
if (skipCoverage) {
- desc->fAttribBindings &= ~(GrDrawState::kEdge_AttribBindingsBit |
- GrDrawState::kCoverage_AttribBindingsBit);
+ desc->fAttribBindings &= ~(GrDrawState::kCoverage_AttribBindingsBit);
}
bool colorIsTransBlack = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag);
@@ -118,12 +117,10 @@ void GrGLProgram::BuildDesc(const GrDrawState& drawState,
int lastEnabledStage = -1;
- if (!skipCoverage && (desc->fAttribBindings & GrDrawState::kEdge_AttribBindingsBit)) {
- desc->fVertexEdgeType = drawState.getVertexEdgeType();
+ if (!skipCoverage) {
desc->fDiscardIfOutsideEdge = drawState.getStencil().doesWrite();
} else {
// Use canonical values when edge-aa is not enabled to avoid program cache misses.
- desc->fVertexEdgeType = GrDrawState::kHairLine_EdgeType;
desc->fDiscardIfOutsideEdge = false;
}
@@ -167,8 +164,7 @@ void GrGLProgram::BuildDesc(const GrDrawState& drawState,
// other coverage inputs
if (!hasCoverage) {
- hasCoverage = requiresAttributeCoverage ||
- (desc->fAttribBindings & GrDrawState::kEdge_AttribBindingsBit);
+ hasCoverage = requiresAttributeCoverage;
}
if (hasCoverage) {
@@ -207,9 +203,6 @@ void GrGLProgram::BuildDesc(const GrDrawState& drawState,
} else {
desc->fCoverageAttributeIndex = GrDrawState::kCoverageOverrideAttribIndexValue;
}
- if (desc->fAttribBindings & GrDrawState::kEdge_AttribBindingsBit) {
- desc->fEdgeAttributeIndex = drawState.getAttribIndex(GrDrawState::kEdge_AttribIndex);
- }
if (desc->fAttribBindings & GrDrawState::kLocalCoords_AttribBindingsBit) {
desc->fLocalCoordsAttributeIndex = drawState.getAttribIndex(GrDrawState::kLocalCoords_AttribIndex);
}
@@ -227,10 +220,6 @@ void GrGLProgram::BuildDesc(const GrDrawState& drawState,
GrAssert(desc->fCoverageAttributeIndex < GrDrawState::kVertexAttribCnt);
GrAssert(kAttribLayouts[vertexAttribs[desc->fCoverageAttributeIndex].fType].fCount == 4);
}
- if (desc->fAttribBindings & GrDrawState::kEdge_AttribBindingsBit) {
- GrAssert(desc->fEdgeAttributeIndex < GrDrawState::kVertexAttribCnt);
- GrAssert(kAttribLayouts[vertexAttribs[desc->fEdgeAttributeIndex].fType].fCount == 4);
- }
if (desc->fAttribBindings & GrDrawState::kLocalCoords_AttribBindingsBit) {
GrAssert(desc->fLocalCoordsAttributeIndex < GrDrawState::kVertexAttribCnt);
GrAssert(kAttribLayouts[vertexAttribs[desc->fLocalCoordsAttributeIndex].fType].fCount == 2);
@@ -419,68 +408,6 @@ void add_color_filter(GrGLShaderBuilder* builder,
}
}
-bool GrGLProgram::genEdgeCoverage(SkString* coverageVar,
- GrGLShaderBuilder* builder) const {
- if (fDesc.fAttribBindings & GrDrawState::kEdge_AttribBindingsBit) {
- const char *vsName, *fsName;
- builder->addVarying(kVec4f_GrSLType, "Edge", &vsName, &fsName);
- builder->addAttribute(kVec4f_GrSLType, EDGE_ATTR_NAME);
- builder->vsCodeAppendf("\t%s = " EDGE_ATTR_NAME ";\n", vsName);
- switch (fDesc.fVertexEdgeType) {
- case GrDrawState::kHairLine_EdgeType:
- builder->fsCodeAppendf("\tfloat edgeAlpha = abs(dot(vec3(%s.xy,1), %s.xyz));\n",
- builder->fragmentPosition(), fsName);
- builder->fsCodeAppendf("\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
- break;
- case GrDrawState::kQuad_EdgeType:
- builder->fsCodeAppendf("\tfloat edgeAlpha;\n");
- // keep the derivative instructions outside the conditional
- builder->fsCodeAppendf("\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
- builder->fsCodeAppendf("\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
- builder->fsCodeAppendf("\tif (%s.z > 0.0 && %s.w > 0.0) {\n", fsName, fsName);
- // today we know z and w are in device space. We could use derivatives
- builder->fsCodeAppendf("\t\tedgeAlpha = min(min(%s.z, %s.w) + 0.5, 1.0);\n", fsName,
- fsName);
- builder->fsCodeAppendf ("\t} else {\n");
- builder->fsCodeAppendf("\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
- "\t\t 2.0*%s.x*duvdy.x - duvdy.y);\n",
- fsName, fsName);
- builder->fsCodeAppendf("\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName, fsName);
- builder->fsCodeAppendf("\t\tedgeAlpha = clamp(0.5 - edgeAlpha / length(gF), 0.0, 1.0);\n"
- "\t}\n");
- if (kES2_GrGLBinding == fContext.info().binding()) {
- builder->fHeader.append("#extension GL_OES_standard_derivatives: enable\n");
- }
- break;
- case GrDrawState::kHairQuad_EdgeType:
- builder->fsCodeAppendf("\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
- builder->fsCodeAppendf("\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
- builder->fsCodeAppendf("\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
- "\t 2.0*%s.x*duvdy.x - duvdy.y);\n",
- fsName, fsName);
- builder->fsCodeAppendf("\tfloat edgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName,
- fsName);
- builder->fsCodeAppend("\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / dot(gF, gF));\n");
- builder->fsCodeAppend("\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
- if (kES2_GrGLBinding == fContext.info().binding()) {
- builder->fHeader.printf("#extension GL_OES_standard_derivatives: enable\n");
- }
- break;
- default:
- GrCrash("Unknown Edge Type!");
- break;
- }
- if (fDesc.fDiscardIfOutsideEdge) {
- builder->fsCodeAppend("\tif (edgeAlpha <= 0.0) {\n\t\tdiscard;\n\t}\n");
- }
- *coverageVar = "edgeAlpha";
- return true;
- } else {
- coverageVar->reset();
- return false;
- }
-}
-
void GrGLProgram::genInputColor(GrGLShaderBuilder* builder, SkString* inColor) {
switch (fDesc.fColorInput) {
case GrGLProgram::Desc::kAttribute_ColorInput: {
@@ -834,19 +761,15 @@ bool GrGLProgram::genProgram(const GrEffectStage* stages[]) {
if (!wroteFragColorZero || Desc::kNone_DualSrcOutput != fDesc.fDualSrcOutput) {
if (!coverageIsZero) {
- bool inCoverageIsScalar = this->genEdgeCoverage(&inCoverage, &builder);
-
switch (fDesc.fCoverageInput) {
case Desc::kSolidWhite_ColorInput:
// empty string implies solid white
break;
case Desc::kAttribute_ColorInput:
gen_attribute_coverage(&builder, &inCoverage);
- inCoverageIsScalar = false;
break;
case Desc::kUniform_ColorInput:
this->genUniformCoverage(&builder, &inCoverage);
- inCoverageIsScalar = false;
break;
default:
GrCrash("Unexpected input coverage.");
@@ -861,13 +784,6 @@ bool GrGLProgram::genProgram(const GrEffectStage* stages[]) {
outCoverage.appendS32(s);
builder.fsCodeAppendf("\tvec4 %s;\n", outCoverage.c_str());
- // stages don't know how to deal with a scalar input. (Maybe they should. We
- // could pass a GrGLShaderVar)
- if (inCoverageIsScalar) {
- builder.fsCodeAppendf("\tvec4 %s4 = vec4(%s);\n",
- inCoverage.c_str(), inCoverage.c_str());
- inCoverage.append("4");
- }
builder.setCurrentStage(s);
fEffects[s] = builder.createAndEmitGLEffect(
*stages[s],
@@ -984,9 +900,6 @@ bool GrGLProgram::bindOutputsAttribsAndLinkProgram(const GrGLShaderBuilder& buil
GL_CALL(BindAttribLocation(fProgramID, fDesc.fColorAttributeIndex, COL_ATTR_NAME));
GL_CALL(BindAttribLocation(fProgramID, fDesc.fCoverageAttributeIndex, COV_ATTR_NAME));
- if (fDesc.fAttribBindings & GrDrawState::kEdge_AttribBindingsBit) {
- GL_CALL(BindAttribLocation(fProgramID, fDesc.fEdgeAttributeIndex, EDGE_ATTR_NAME));
- }
if (fDesc.fAttribBindings & GrDrawState::kLocalCoords_AttribBindingsBit) {
GL_CALL(BindAttribLocation(fProgramID,
fDesc.fLocalCoordsAttributeIndex,
diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h
index 9fd01fd816..a6ece6ccbf 100644
--- a/src/gpu/gl/GrGLProgram.h
+++ b/src/gpu/gl/GrGLProgram.h
@@ -165,8 +165,6 @@ public:
kDualSrcOutputCnt
};
- // TODO: remove these two members when edge-aa can be rewritten as a GrEffect.
- GrDrawState::VertexEdgeType fVertexEdgeType;
// should the FS discard if the edge-aa coverage is zero (to avoid stencil manipulation)
bool fDiscardIfOutsideEdge;
@@ -191,7 +189,6 @@ public:
int8_t fPositionAttributeIndex;
int8_t fColorAttributeIndex;
int8_t fCoverageAttributeIndex;
- int8_t fEdgeAttributeIndex;
int8_t fLocalCoordsAttributeIndex;
friend class GrGLProgram;
@@ -225,11 +222,6 @@ private:
void genUniformCoverage(GrGLShaderBuilder* segments, SkString* inOutCoverage);
- // generates code to compute coverage based on edge AA. Returns true if edge coverage was
- // inserted in which case coverageVar will be updated to refer to a scalar. Otherwise,
- // coverageVar is set to an empty string.
- bool genEdgeCoverage(SkString* coverageVar, GrGLShaderBuilder* builder) const;
-
// Creates a GL program ID, binds shader attributes to GL vertex attrs, and links the program
bool bindOutputsAttribsAndLinkProgram(const GrGLShaderBuilder& builder,
bool bindColorOut,
diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp
index 1270b9305f..50ba9c3dce 100644
--- a/tests/GLProgramsTest.cpp
+++ b/tests/GLProgramsTest.cpp
@@ -39,17 +39,10 @@ void GrGLProgram::Desc::setRandom(SkMWCRandom* random,
fExperimentalGS = gpu->caps()->geometryShaderSupport() && random->nextBool();
#endif
- bool edgeAA = random->nextBool();
- if (edgeAA) {
- fAttribBindings |= GrDrawState::kEdge_AttribBindingsBit;
- if (gpu->caps()->shaderDerivativeSupport()) {
- fVertexEdgeType = (GrDrawState::VertexEdgeType)
- random->nextULessThan(GrDrawState::kVertexEdgeTypeCnt);
- fDiscardIfOutsideEdge = random->nextBool();
- } else {
- fVertexEdgeType = GrDrawState::kHairLine_EdgeType;
- fDiscardIfOutsideEdge = false;
- }
+ if (gpu->caps()->shaderDerivativeSupport()) {
+ fDiscardIfOutsideEdge = random->nextBool();
+ } else {
+ fDiscardIfOutsideEdge = false;
}
if (gpu->caps()->dualSourceBlendingSupport()) {
@@ -84,10 +77,6 @@ void GrGLProgram::Desc::setRandom(SkMWCRandom* random,
fCoverageAttributeIndex = attributeIndex;
++attributeIndex;
}
- if (fAttribBindings & GrDrawState::kEdge_AttribBindingsBit) {
- fEdgeAttributeIndex = attributeIndex;
- ++attributeIndex;
- }
if (fAttribBindings & GrDrawState::kLocalCoords_AttribBindingsBit) {
fLocalCoordsAttributeIndex = attributeIndex;
++attributeIndex;