aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar senorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-05-12 15:49:15 +0000
committerGravatar senorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-05-12 15:49:15 +0000
commit92e0f222fb311a296acd081c1216d6b9652347eb (patch)
tree17894c6e33a9b8a0cc72e6a03a775aee550db807
parent189520db79e09da6281dabee959397cc48c72e3d (diff)
Edge antialiasing for convex shapes in Ganesh
This patch implements edge antialiasing for convex shapes, using the fragment shader to compare against the edge equations for each triangle. Currently, it only works for flat shaded primitives (i.e., it was not integrated into the "active stages" path). The skia.gyp changes cause this code to be compiled into SampleApp, but do not enable the tesselated path by default. Notes: the SkOSWindow_Unix.cpp change is to silence a valgrind warning about memcpy() with overlapping regions. The GrBinHashKey change is to avoid running a two-pass hash (GrProgramDesc is now 52 bytes or so, exceeding the 32 byte default size). Review URL: http://codereview.appspot.com/4519054/ git-svn-id: http://skia.googlecode.com/svn/trunk@1314 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r--gpu/include/GrDrawTarget.h27
-rw-r--r--gpu/include/GrTesselatedPathRenderer.h3
-rw-r--r--gpu/src/GrDrawTarget.cpp12
-rw-r--r--gpu/src/GrGLProgram.cpp30
-rw-r--r--gpu/src/GrGLProgram.h3
-rw-r--r--gpu/src/GrGpuGLShaders.cpp21
-rw-r--r--gpu/src/GrGpuGLShaders.h3
-rw-r--r--gpu/src/GrTesselatedPathRenderer.cpp113
-rw-r--r--gyp/skia.gyp10
-rw-r--r--src/utils/unix/SkOSWindow_Unix.cpp2
10 files changed, 203 insertions, 21 deletions
diff --git a/gpu/include/GrDrawTarget.h b/gpu/include/GrDrawTarget.h
index e8f1793759..93b381dd9f 100644
--- a/gpu/include/GrDrawTarget.h
+++ b/gpu/include/GrDrawTarget.h
@@ -66,18 +66,22 @@ public:
* default to disabled.
*/
enum StateBits {
- kDither_StateBit = 0x1,//<! Perform color dithering
- kAntialias_StateBit = 0x2,//<! Perform anti-aliasing. The render-
+ kDither_StateBit = 0x01, //<! Perform color dithering
+ kAntialias_StateBit = 0x02, //<! Perform anti-aliasing. The render-
// target must support some form of AA
// (msaa, coverage sampling, etc). For
// GrGpu-created rendertarget/textures
// this is controlled by parameters
// passed to createTexture.
- kClip_StateBit = 0x4,//<! Controls whether drawing is clipped
+ kClip_StateBit = 0x04, //<! Controls whether drawing is clipped
// against the region specified by
// setClip.
- kNoColorWrites_StateBit = 0x8,//<! If set it disables writing colors.
- // Useful while performing stencil ops.
+ kNoColorWrites_StateBit = 0x08, //<! If set it disables writing colors.
+ // Useful while performing stencil
+ // ops.
+ kEdgeAA_StateBit = 0x10, //<! Perform edge anti-aliasing.
+ // Requires the edges to be passed in
+ // setEdgeAAData().
// subclass may use additional bits internally
kDummyStateBit,
@@ -154,6 +158,7 @@ protected:
GrStencilSettings fStencilSettings;
GrMatrix fViewMatrix;
+ float fEdgeAAEdges[18];
bool operator ==(const DrState& s) const {
return 0 == memcmp(this, &s, sizeof(DrState));
}
@@ -362,6 +367,10 @@ public:
return 0 != (fCurrDrawState.fFlagBits & kDither_StateBit);
}
+ bool isAntialiasState() const {
+ return 0 != (fCurrDrawState.fFlagBits & kAntialias_StateBit);
+ }
+
bool isClipState() const {
return 0 != (fCurrDrawState.fFlagBits & kClip_StateBit);
}
@@ -483,6 +492,14 @@ public:
*/
bool canDisableBlend() const;
+ /**
+ * Sets the edge data required for edge antialiasing.
+ *
+ * @param edges 3 * 6 float values, representing the edge
+ * equations in Ax + By + C form
+ */
+ void setEdgeAAData(const float edges[18]);
+
private:
static const int TEX_COORD_BIT_CNT = kNumStages*kMaxTexCoords;
public:
diff --git a/gpu/include/GrTesselatedPathRenderer.h b/gpu/include/GrTesselatedPathRenderer.h
index 3efc471b4c..accd114e4c 100644
--- a/gpu/include/GrTesselatedPathRenderer.h
+++ b/gpu/include/GrTesselatedPathRenderer.h
@@ -39,6 +39,9 @@ public:
GrPathIter* path,
GrPathFill fill,
const GrPoint* translate);
+ virtual bool supportsAA(GrDrawTarget* target,
+ GrPathIter* path,
+ GrPathFill fill);
};
#endif
diff --git a/gpu/src/GrDrawTarget.cpp b/gpu/src/GrDrawTarget.cpp
index 668dc3a415..5e515137dc 100644
--- a/gpu/src/GrDrawTarget.cpp
+++ b/gpu/src/GrDrawTarget.cpp
@@ -478,6 +478,11 @@ void GrDrawTarget::setIndexSourceToBuffer(const GrIndexBuffer* buffer) {
///////////////////////////////////////////////////////////////////////////////
bool GrDrawTarget::canDisableBlend() const {
+ // If we're using edge antialiasing, we can't force blend off.
+ if (fCurrDrawState.fFlagBits & kAntialias_StateBit) {
+ return false;
+ }
+
if ((kOne_BlendCoeff == fCurrDrawState.fSrcBlend) &&
(kZero_BlendCoeff == fCurrDrawState.fDstBlend)) {
return true;
@@ -524,6 +529,13 @@ bool GrDrawTarget::canDisableBlend() const {
// ...then we disable blend.
return true;
}
+
+///////////////////////////////////////////////////////////////////////////////
+void GrDrawTarget::setEdgeAAData(const float edges[18]) {
+ memcpy(fCurrDrawState.fEdgeAAEdges, edges, sizeof(fCurrDrawState.fEdgeAAEdges));
+}
+
+
///////////////////////////////////////////////////////////////////////////////
void GrDrawTarget::drawRect(const GrRect& rect,
const GrMatrix* matrix,
diff --git a/gpu/src/GrGLProgram.cpp b/gpu/src/GrGLProgram.cpp
index 1c0db251b7..ce4e7dbd03 100644
--- a/gpu/src/GrGLProgram.cpp
+++ b/gpu/src/GrGLProgram.cpp
@@ -54,6 +54,7 @@ const char* GrShaderPrecision() {
#define POS_ATTR_NAME "aPosition"
#define COL_ATTR_NAME "aColor"
#define COL_UNI_NAME "uColor"
+#define EDGES_UNI_NAME "uEdges"
#define COL_FILTER_UNI_NAME "uColorFilter"
static inline void tex_attr_name(int coordIdx, GrStringBuilder* s) {
@@ -269,6 +270,10 @@ bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const {
break;
}
+ if (fProgramDesc.fUsesEdgeAA) {
+ segments.fFSUnis.append("uniform vec3 " EDGES_UNI_NAME "[6];\n");
+ }
+
if (fProgramDesc.fEmitsPointSize){
segments.fVSCode.append("\tgl_PointSize = 1.0;\n");
}
@@ -352,6 +357,23 @@ bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const {
}
} else {
+ if (fProgramDesc.fUsesEdgeAA) {
+ // FIXME: put the a's in a loop
+ segments.fFSCode.append(
+ "\tvec3 pos = vec3(gl_FragCoord.xy, 1);\n"
+ "\tfloat a0 = clamp(dot(uEdges[0], pos), 0.0, 1.0);\n"
+ "\tfloat a1 = clamp(dot(uEdges[1], pos), 0.0, 1.0);\n"
+ "\tfloat a2 = clamp(dot(uEdges[2], pos), 0.0, 1.0);\n"
+ "\tfloat a3 = clamp(dot(uEdges[3], pos), 0.0, 1.0);\n"
+ "\tfloat a4 = clamp(dot(uEdges[4], pos), 0.0, 1.0);\n"
+ "\tfloat a5 = clamp(dot(uEdges[5], pos), 0.0, 1.0);\n"
+ "\tfloat edgeAlpha = min(min(a0 * a1, a2 * a3), a4 * a5);\n");
+ if (inColor.size()) {
+ inColor.append(" * edgeAlpha");
+ } else {
+ inColor = "vec4(edgeAlpha)";
+ }
+ }
// we may not have any incoming color
const char * incomingColor = (inColor.size() ? inColor.c_str()
: "vec4(1,1,1,1)");
@@ -583,6 +605,14 @@ void GrGLProgram::getUniformLocationsAndInitCache(CachedData* programData) const
GrAssert(kUnusedUniform != programData->fUniLocations.fColorFilterUni);
}
+ if (fProgramDesc.fUsesEdgeAA) {
+ programData->fUniLocations.fEdgesUni =
+ GR_GL(GetUniformLocation(progID, EDGES_UNI_NAME));
+ GrAssert(kUnusedUniform != programData->fUniLocations.fEdgesUni);
+ } else {
+ programData->fUniLocations.fEdgesUni = kUnusedUniform;
+ }
+
for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
StageUniLocations& locations = programData->fUniLocations.fStages[s];
if (fProgramDesc.fStages[s].fEnabled) {
diff --git a/gpu/src/GrGLProgram.h b/gpu/src/GrGLProgram.h
index 08902387e7..1611ca21c4 100644
--- a/gpu/src/GrGLProgram.h
+++ b/gpu/src/GrGLProgram.h
@@ -108,6 +108,7 @@ private:
} fColorType;
bool fEmitsPointSize;
+ bool fUsesEdgeAA;
SkXfermode::Mode fColorFilterXfermode;
@@ -163,11 +164,13 @@ public:
struct UniLocations {
GrGLint fViewMatrixUni;
GrGLint fColorUni;
+ GrGLint fEdgesUni;
GrGLint fColorFilterUni;
StageUniLocations fStages[GrDrawTarget::kNumStages];
void reset() {
fViewMatrixUni = kUnusedUniform;
fColorUni = kUnusedUniform;
+ fEdgesUni = kUnusedUniform;
fColorFilterUni = kUnusedUniform;
for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
fStages[s].reset();
diff --git a/gpu/src/GrGpuGLShaders.cpp b/gpu/src/GrGpuGLShaders.cpp
index 937c8ed422..8965b06520 100644
--- a/gpu/src/GrGpuGLShaders.cpp
+++ b/gpu/src/GrGpuGLShaders.cpp
@@ -36,7 +36,7 @@ private:
#if GR_DEBUG
typedef GrBinHashKey<Entry, 4> ProgramHashKey; // Flex the dynamic allocation muscle in debug
#else
- typedef GrBinHashKey<Entry, 32> ProgramHashKey;
+ typedef GrBinHashKey<Entry, 64> ProgramHashKey;
#endif
class Entry : public ::GrNoncopyable {
@@ -396,6 +396,22 @@ void GrGpuGLShaders::flushTexelSize(int s) {
}
}
+void GrGpuGLShaders::flushEdgeAAData() {
+ const int& uni = fProgramData->fUniLocations.fEdgesUni;
+ if (GrGLProgram::kUnusedUniform != uni) {
+ float edges[18];
+ memcpy(edges, fCurrDrawState.fEdgeAAEdges, sizeof(edges));
+ // Flip the edges in Y
+ float height = fCurrDrawState.fRenderTarget->height();
+ for (int i = 0; i < 6; ++i) {
+ float b = edges[i * 3 + 1];
+ edges[i * 3 + 1] = -b;
+ edges[i * 3 + 2] += b * height;
+ }
+ GR_GL(Uniform3fv(uni, 6, edges));
+ }
+}
+
static const float ONE_OVER_255 = 1.f / 255.f;
#define GR_COLOR_TO_VEC4(color) {\
@@ -500,6 +516,7 @@ bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) {
this->flushTexelSize(s);
}
+ this->flushEdgeAAData();
resetDirtyFlags();
return true;
}
@@ -632,6 +649,8 @@ void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
desc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
}
+ desc.fUsesEdgeAA = fCurrDrawState.fFlagBits & kEdgeAA_StateBit;
+
for (int s = 0; s < kNumStages; ++s) {
GrGLProgram::ProgramDesc::StageDesc& stage = desc.fStages[s];
diff --git a/gpu/src/GrGpuGLShaders.h b/gpu/src/GrGpuGLShaders.h
index a1bcaf08be..bb3024faf9 100644
--- a/gpu/src/GrGpuGLShaders.h
+++ b/gpu/src/GrGpuGLShaders.h
@@ -63,6 +63,9 @@ private:
// flushes the normalized texel size
void flushTexelSize(int stage);
+ // flushes the edges for edge AA
+ void flushEdgeAAData();
+
static void DeleteProgram(GrGLProgram::CachedData* programData);
void ProgramUnitTest();
diff --git a/gpu/src/GrTesselatedPathRenderer.cpp b/gpu/src/GrTesselatedPathRenderer.cpp
index 8ed2c2249e..3993adb5d9 100644
--- a/gpu/src/GrTesselatedPathRenderer.cpp
+++ b/gpu/src/GrTesselatedPathRenderer.cpp
@@ -55,8 +55,8 @@ static void combineData(GLdouble coords[3], void* vertexData[4],
{
PolygonData* polygonData = static_cast<PolygonData*>(data);
int index = polygonData->fVertices->count();
- *polygonData->fVertices->append() = GrPoint(static_cast<float>(coords[0]),
- static_cast<float>(coords[1]));
+ *polygonData->fVertices->append() = GrPoint::Make(static_cast<float>(coords[0]),
+ static_cast<float>(coords[1]));
*outData = reinterpret_cast<void*>(index);
}
@@ -83,6 +83,59 @@ static unsigned fill_type_to_glu_winding_rule(GrPathFill fill) {
GrTesselatedPathRenderer::GrTesselatedPathRenderer() {
}
+class Edge {
+ public:
+ Edge() {}
+ Edge(float x, float y, float z) : fX(x), fY(y), fZ(z) {}
+ GrPoint intersect(const Edge& other) {
+ return GrPoint::Make(
+ (fY * other.fZ - other.fY * fZ) / (fX * other.fY - other.fX * fY),
+ (fX * other.fZ - other.fX * fZ) / (other.fX * fY - fX * other.fY));
+ }
+ float fX, fY, fZ;
+};
+
+typedef GrTDArray<Edge> EdgeArray;
+
+bool isCCW(const GrPoint* v)
+{
+ GrVec v1 = v[1] - v[0];
+ GrVec v2 = v[2] - v[1];
+ return v1.cross(v2) < 0;
+}
+
+static size_t computeEdgesAndOffsetVertices(const GrMatrix& matrix,
+ const GrMatrix& inverse,
+ GrPoint* vertices,
+ size_t numVertices,
+ EdgeArray* edges)
+{
+ GrPoint p = vertices[numVertices - 1];
+ matrix.mapPoints(&p, 1);
+ float sign = isCCW(vertices) ? -1.0f : 1.0f;
+ for (size_t i = 0; i < numVertices; ++i) {
+ GrPoint q = vertices[i];
+ matrix.mapPoints(&q, 1);
+ if (p == q) continue;
+ GrVec tangent = GrVec::Make(p.fY - q.fY, q.fX - p.fX);
+ float scale = sign / tangent.length();
+ float cross2 = p.fX * q.fY - q.fX * p.fY;
+ Edge edge(tangent.fX * scale,
+ tangent.fY * scale,
+ cross2 * scale + 0.5f);
+ *edges->append() = edge;
+ p = q;
+ }
+ Edge prev_edge = *edges->back();
+ for (size_t i = 0; i < edges->count(); ++i) {
+ Edge edge = edges->at(i);
+ vertices[i] = prev_edge.intersect(edge);
+ inverse.mapPoints(&vertices[i], 1);
+ prev_edge = edge;
+ }
+ return edges->count();
+}
+
void GrTesselatedPathRenderer::drawPath(GrDrawTarget* target,
GrDrawTarget::StageBitfield stages,
GrPathIter* path,
@@ -193,10 +246,10 @@ FINISHED:
if (target->getViewInverse(&vmi)) {
vmi.mapRect(&bounds);
}
- *vert++ = GrPoint(bounds.fLeft, bounds.fTop);
- *vert++ = GrPoint(bounds.fLeft, bounds.fBottom);
- *vert++ = GrPoint(bounds.fRight, bounds.fBottom);
- *vert++ = GrPoint(bounds.fRight, bounds.fTop);
+ *vert++ = GrPoint::Make(bounds.fLeft, bounds.fTop);
+ *vert++ = GrPoint::Make(bounds.fLeft, bounds.fBottom);
+ *vert++ = GrPoint::Make(bounds.fRight, bounds.fBottom);
+ *vert++ = GrPoint::Make(bounds.fRight, bounds.fTop);
subpathVertCount[subpath++] = 4;
}
@@ -205,9 +258,40 @@ FINISHED:
size_t count = vert - base;
+ if (count < 3) {
+ delete[] base;
+ return;
+ }
+
if (subpathCnt == 1 && !inverted && path->convexHint() == kConvex_ConvexHint) {
- target->setVertexSourceToArray(layout, base, count);
- target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, count);
+ if (target->isAntialiasState()) {
+ target->enableState(GrDrawTarget::kEdgeAA_StateBit);
+ EdgeArray edges;
+ GrMatrix inverse, matrix = target->getViewMatrix();
+ target->getViewInverse(&inverse);
+
+ count = computeEdgesAndOffsetVertices(matrix, inverse, base, count, &edges);
+ GrPoint triangle[3];
+ triangle[0] = base[0];
+ Edge triangleEdges[6];
+ triangleEdges[0] = *edges.back();
+ triangleEdges[1] = edges[0];
+ for (size_t i = 1; i < count - 1; i++) {
+ triangle[1] = base[i];
+ triangle[2] = base[i + 1];
+ triangleEdges[2] = edges[i - 1];
+ triangleEdges[3] = edges[i];
+ triangleEdges[4] = edges[i];
+ triangleEdges[5] = edges[i + 1];
+ target->setVertexSourceToArray(layout, triangle, 3);
+ target->setEdgeAAData(&triangleEdges[0].fX);
+ target->drawNonIndexed(kTriangles_PrimitiveType, 0, 3);
+ }
+ target->disableState(GrDrawTarget::kEdgeAA_StateBit);
+ } else {
+ target->setVertexSourceToArray(layout, base, count);
+ target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, count);
+ }
delete[] base;
return;
}
@@ -241,7 +325,7 @@ FINISHED:
int end = start + subpathVertCount[sp];
for (; i < end; ++i) {
double* inVertex = &inVertices[i * 3];
- *vertices.append() = GrPoint(inVertex[0], inVertex[1]);
+ *vertices.append() = GrPoint::Make(inVertex[0], inVertex[1]);
internal_gluTessVertex(tess, inVertex, reinterpret_cast<void*>(i));
}
internal_gluTessEndContour(tess);
@@ -275,3 +359,14 @@ void GrTesselatedPathRenderer::drawPathToStencil(GrDrawTarget* target,
const GrPoint* translate) {
GrAlwaysAssert(!"multipass stencil should not be needed");
}
+
+bool GrTesselatedPathRenderer::supportsAA(GrDrawTarget* target,
+ GrPathIter* path,
+ GrPathFill fill) {
+ int subpathCnt = 0;
+ int tol = GrPathUtils::gTolerance;
+ GrPathUtils::worstCasePointCount(path, &subpathCnt, tol);
+ return (subpathCnt == 1 &&
+ !IsFillInverted(fill) &&
+ path->convexHint() == kConvex_ConvexHint);
+}
diff --git a/gyp/skia.gyp b/gyp/skia.gyp
index c37d567aee..7247828bb1 100644
--- a/gyp/skia.gyp
+++ b/gyp/skia.gyp
@@ -904,9 +904,9 @@
'../include/core',
'../include/config',
],
- #'dependencies': [
- # 'libtess',
- #],
+ 'dependencies': [
+ 'libtess',
+ ],
'sources': [
'../gpu/include/GrAllocator.h',
'../gpu/include/GrAllocPool.h',
@@ -959,7 +959,7 @@
'../gpu/include/GrTArray.h',
'../gpu/include/GrTBSearch.h',
'../gpu/include/GrTDArray.h',
- #'../gpu/include/GrTesselatedPathRenderer.h',
+ '../gpu/include/GrTesselatedPathRenderer.h',
'../gpu/include/GrTextContext.h',
'../gpu/include/GrTextStrike.h',
'../gpu/include/GrTexture.h',
@@ -1008,7 +1008,7 @@
'../gpu/src/GrRedBlackTree.h',
'../gpu/src/GrResource.cpp',
'../gpu/src/GrStencil.cpp',
- #'../gpu/src/GrTesselatedPathRenderer.cpp',
+ '../gpu/src/GrTesselatedPathRenderer.cpp',
'../gpu/src/GrTextContext.cpp',
'../gpu/src/GrTextStrike.cpp',
'../gpu/src/GrTextStrike_impl.h',
diff --git a/src/utils/unix/SkOSWindow_Unix.cpp b/src/utils/unix/SkOSWindow_Unix.cpp
index 5f63b539f9..4ec0c74306 100644
--- a/src/utils/unix/SkOSWindow_Unix.cpp
+++ b/src/utils/unix/SkOSWindow_Unix.cpp
@@ -88,7 +88,7 @@ void SkOSWindow::restartLoop()
{
// We have a new window, so we need to set the title again and restart the
// loop.
- this->setTitle(this->getTitle());
+ this->onSetTitle(this->getTitle());
fRestart = true;
}