aboutsummaryrefslogtreecommitdiffhomepage
path: root/gpu/src
diff options
context:
space:
mode:
Diffstat (limited to 'gpu/src')
-rw-r--r--gpu/src/GrContext.cpp96
-rw-r--r--gpu/src/GrDrawTarget.cpp157
-rw-r--r--gpu/src/GrDrawTarget.h177
-rw-r--r--gpu/src/GrGLProgram.cpp20
-rw-r--r--gpu/src/GrGLProgram.h5
-rw-r--r--gpu/src/GrGpuGLFixed.cpp6
-rw-r--r--gpu/src/GrGpuGLShaders.cpp61
7 files changed, 372 insertions, 150 deletions
diff --git a/gpu/src/GrContext.cpp b/gpu/src/GrContext.cpp
index d9fb9e85c8..3f5ab5471b 100644
--- a/gpu/src/GrContext.cpp
+++ b/gpu/src/GrContext.cpp
@@ -677,6 +677,7 @@ bool GrContext::doOffscreenAA(GrDrawTarget* target,
return false;
}
if (disable_coverage_aa_for_blend(target)) {
+ GrPrintf("Turning off AA to correctly apply blend.\n");
return false;
}
return true;
@@ -937,18 +938,6 @@ static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
verts[9] = verts[1];
}
-static GrColor getColorForMesh(const GrPaint& paint) {
- // FIXME: This was copied from SkGpuDevice, seems like
- // we should have already smeared a in caller if that
- // is what is desired.
- if (paint.hasTexture()) {
- unsigned a = GrColorUnpackA(paint.fColor);
- return GrColorPackRGBA(a, a, a, a);
- } else {
- return paint.fColor;
- }
-}
-
static void setInsetFan(GrPoint* pts, size_t stride,
const GrRect& r, GrScalar dx, GrScalar dy) {
pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
@@ -1019,11 +1008,26 @@ GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
return fAAStrokeRectIndexBuffer;
}
+static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
+ bool useCoverage) {
+ GrVertexLayout layout = 0;
+ for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
+ if (NULL != target->getTexture(s)) {
+ layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
+ }
+ }
+ if (useCoverage) {
+ layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
+ } else {
+ layout |= GrDrawTarget::kColor_VertexLayoutBit;
+ }
+ return layout;
+}
+
void GrContext::fillAARect(GrDrawTarget* target,
- const GrPaint& paint,
- const GrRect& devRect) {
- GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
- GrDrawTarget::kColor_VertexLayoutBit;
+ const GrRect& devRect,
+ bool useVertexCoverage) {
+ GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
size_t vsize = GrDrawTarget::VertexSize(layout);
@@ -1051,7 +1055,13 @@ void GrContext::fillAARect(GrDrawTarget* target,
*reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
}
- GrColor innerColor = getColorForMesh(paint);
+ GrColor innerColor;
+ if (useVertexCoverage) {
+ innerColor = GrColorPackRGBA(0,0,0,0xff);
+ } else {
+ innerColor = target->getColor();
+ }
+
verts += 4 * vsize;
for (int i = 0; i < 4; ++i) {
*reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
@@ -1063,16 +1073,15 @@ void GrContext::fillAARect(GrDrawTarget* target,
0, 8, this->aaFillRectIndexCount());
}
-void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
- const GrRect& devRect, const GrVec& devStrokeSize) {
+void GrContext::strokeAARect(GrDrawTarget* target,
+ const GrRect& devRect,
+ const GrVec& devStrokeSize,
+ bool useVertexCoverage) {
const GrScalar& dx = devStrokeSize.fX;
const GrScalar& dy = devStrokeSize.fY;
const GrScalar rx = GrMul(dx, GR_ScalarHalf);
const GrScalar ry = GrMul(dy, GR_ScalarHalf);
- GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
- GrDrawTarget::kColor_VertexLayoutBit;
-
GrScalar spare;
{
GrScalar w = devRect.width() - dx;
@@ -1083,10 +1092,10 @@ void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
if (spare <= 0) {
GrRect r(devRect);
r.inset(-rx, -ry);
- fillAARect(target, paint, r);
+ fillAARect(target, r, useVertexCoverage);
return;
}
-
+ GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
size_t vsize = GrDrawTarget::VertexSize(layout);
GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
@@ -1117,7 +1126,12 @@ void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
*reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
}
- GrColor innerColor = getColorForMesh(paint);
+ GrColor innerColor;
+ if (useVertexCoverage) {
+ innerColor = GrColorPackRGBA(0,0,0,0xff);
+ } else {
+ innerColor = target->getColor();
+ }
verts += 4 * vsize;
for (int i = 0; i < 8; ++i) {
*reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
@@ -1146,7 +1160,8 @@ static bool apply_aa_to_rect(GrDrawTarget* target,
GrScalar width,
const GrMatrix* matrix,
GrMatrix* combinedMatrix,
- GrRect* devRect) {
+ GrRect* devRect,
+ bool* useVertexCoverage) {
// we use a simple alpha ramp to do aa on axis-aligned rects
// do AA with alpha ramp if the caller requested AA, the rect
// will be axis-aligned,the render target is not
@@ -1156,8 +1171,22 @@ static bool apply_aa_to_rect(GrDrawTarget* target,
return false;
}
+ // we are keeping around the "tweak the alpha" trick because
+ // it is our only hope for the fixed-pipe implementation.
+ // In a shader implementation we can give a separate coverage input
+ *useVertexCoverage = false;
if (!target->canTweakAlphaForCoverage()) {
- return false;
+ if (target->getCaps().fSupportPerVertexCoverage) {
+ if (disable_coverage_aa_for_blend(target)) {
+ GrPrintf("Turning off AA to correctly apply blend.\n");
+ return false;
+ } else {
+ *useVertexCoverage = true;
+ }
+ } else {
+ GrPrintf("Rect AA dropped because no support for coverage.\n");
+ return false;
+ }
}
if (target->getRenderTarget()->isMultisampled()) {
@@ -1204,8 +1233,9 @@ void GrContext::drawRect(const GrPaint& paint,
GrRect devRect = rect;
GrMatrix combinedMatrix;
+ bool useVertexCoverage;
bool doAA = apply_aa_to_rect(target, rect, width, matrix,
- &combinedMatrix, &devRect);
+ &combinedMatrix, &devRect, &useVertexCoverage);
if (doAA) {
GrDrawTarget::AutoViewMatrixRestore avm(target);
@@ -1225,9 +1255,9 @@ void GrContext::drawRect(const GrPaint& paint,
} else {
strokeSize.set(GR_Scalar1, GR_Scalar1);
}
- strokeAARect(target, paint, devRect, strokeSize);
+ strokeAARect(target, devRect, strokeSize, useVertexCoverage);
} else {
- fillAARect(target, paint, devRect);
+ fillAARect(target, devRect, useVertexCoverage);
}
return;
}
@@ -1406,12 +1436,11 @@ void GrContext::drawVertices(const GrPaint& paint,
}
int texOffsets[GrDrawTarget::kMaxTexCoords];
int colorOffset;
- int edgeOffset;
GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
texOffsets,
&colorOffset,
- &edgeOffset);
- GrAssert(-1 == edgeOffset);
+ NULL,
+ NULL);
void* curVertex = geo.vertices();
for (int i = 0; i < vertexCount; ++i) {
@@ -1462,6 +1491,7 @@ void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
// aa. If we have some future driver-mojo path AA that can do the right
// thing WRT to the blend then we'll need some query on the PR.
if (disable_coverage_aa_for_blend(target)) {
+ GrPrintf("Turning off AA to correctly apply blend.\n");
target->disableState(GrDrawTarget::kAntialias_StateBit);
}
diff --git a/gpu/src/GrDrawTarget.cpp b/gpu/src/GrDrawTarget.cpp
index 79b3da8482..2169fc7bdd 100644
--- a/gpu/src/GrDrawTarget.cpp
+++ b/gpu/src/GrDrawTarget.cpp
@@ -88,12 +88,30 @@ size_t GrDrawTarget::VertexSize(GrVertexLayout vertexLayout) {
if (vertexLayout & kColor_VertexLayoutBit) {
size += sizeof(GrColor);
}
+ if (vertexLayout & kCoverage_VertexLayoutBit) {
+ size += sizeof(GrColor);
+ }
if (vertexLayout & kEdge_VertexLayoutBit) {
size += 4 * sizeof(GrScalar);
}
return size;
}
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Functions for computing offsets of various components from the layout
+ * bitfield.
+ *
+ * Order of vertex components:
+ * Position
+ * Tex Coord 0
+ * ...
+ * Tex Coord kMaxTexCoords-1
+ * Color
+ * Coverage
+ */
+
int GrDrawTarget::VertexStageCoordOffset(int stage, GrVertexLayout vertexLayout) {
GrAssert(check_layout(vertexLayout));
if (StagePosAsTexCoordVertexLayoutBit(stage) & vertexLayout) {
@@ -121,7 +139,6 @@ int GrDrawTarget::VertexStageCoordOffset(int stage, GrVertexLayout vertexLayout)
int GrDrawTarget::VertexColorOffset(GrVertexLayout vertexLayout) {
GrAssert(check_layout(vertexLayout));
- // color is after the pos and tex coords
if (vertexLayout & kColor_VertexLayoutBit) {
int vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ?
sizeof(GrGpuTextVertex) :
@@ -131,6 +148,23 @@ int GrDrawTarget::VertexColorOffset(GrVertexLayout vertexLayout) {
return -1;
}
+int GrDrawTarget::VertexCoverageOffset(GrVertexLayout vertexLayout) {
+ GrAssert(check_layout(vertexLayout));
+
+ if (vertexLayout & kCoverage_VertexLayoutBit) {
+ int vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ?
+ sizeof(GrGpuTextVertex) :
+ sizeof(GrPoint);
+
+ int offset = vecSize * (num_tex_coords(vertexLayout) + 1);
+ if (vertexLayout & kColor_VertexLayoutBit) {
+ offset += sizeof(GrColor);
+ }
+ return offset;
+ }
+ return -1;
+}
+
int GrDrawTarget::VertexEdgeOffset(GrVertexLayout vertexLayout) {
GrAssert(check_layout(vertexLayout));
@@ -143,21 +177,21 @@ int GrDrawTarget::VertexEdgeOffset(GrVertexLayout vertexLayout) {
if (vertexLayout & kColor_VertexLayoutBit) {
offset += sizeof(GrColor);
}
+ if (vertexLayout & kCoverage_VertexLayoutBit) {
+ offset += sizeof(GrColor);
+ }
return offset;
}
return -1;
}
int GrDrawTarget::VertexSizeAndOffsetsByIdx(GrVertexLayout vertexLayout,
- int texCoordOffsetsByIdx[kMaxTexCoords],
- int* colorOffset,
- int* edgeOffset) {
+ int texCoordOffsetsByIdx[kMaxTexCoords],
+ int* colorOffset,
+ int* coverageOffset,
+ int* edgeOffset) {
GrAssert(check_layout(vertexLayout));
- GrAssert(NULL != texCoordOffsetsByIdx);
- GrAssert(NULL != colorOffset);
- GrAssert(NULL != edgeOffset);
-
int vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ?
sizeof(GrGpuTextVertex) :
sizeof(GrPoint);
@@ -165,23 +199,45 @@ int GrDrawTarget::VertexSizeAndOffsetsByIdx(GrVertexLayout vertexLayout,
for (int t = 0; t < kMaxTexCoords; ++t) {
if (tex_coord_idx_mask(t) & vertexLayout) {
- texCoordOffsetsByIdx[t] = size;
+ if (NULL != texCoordOffsetsByIdx) {
+ texCoordOffsetsByIdx[t] = size;
+ }
size += vecSize;
} else {
- texCoordOffsetsByIdx[t] = -1;
+ if (NULL != texCoordOffsetsByIdx) {
+ texCoordOffsetsByIdx[t] = -1;
+ }
}
}
if (kColor_VertexLayoutBit & vertexLayout) {
- *colorOffset = size;
+ if (NULL != colorOffset) {
+ *colorOffset = size;
+ }
+ size += sizeof(GrColor);
+ } else {
+ if (NULL != colorOffset) {
+ *colorOffset = -1;
+ }
+ }
+ if (kCoverage_VertexLayoutBit & vertexLayout) {
+ if (NULL != coverageOffset) {
+ *coverageOffset = size;
+ }
size += sizeof(GrColor);
} else {
- *colorOffset = -1;
+ if (NULL != coverageOffset) {
+ *coverageOffset = -1;
+ }
}
if (kEdge_VertexLayoutBit & vertexLayout) {
- *edgeOffset = size;
+ if (NULL != edgeOffset) {
+ *edgeOffset = size;
+ }
size += 4 * sizeof(GrScalar);
} else {
- *edgeOffset = -1;
+ if (NULL != edgeOffset) {
+ *edgeOffset = -1;
+ }
}
return size;
}
@@ -189,31 +245,35 @@ int GrDrawTarget::VertexSizeAndOffsetsByIdx(GrVertexLayout vertexLayout,
int GrDrawTarget::VertexSizeAndOffsetsByStage(GrVertexLayout vertexLayout,
int texCoordOffsetsByStage[kNumStages],
int* colorOffset,
+ int* coverageOffset,
int* edgeOffset) {
GrAssert(check_layout(vertexLayout));
- GrAssert(NULL != texCoordOffsetsByStage);
- GrAssert(NULL != colorOffset);
- GrAssert(NULL != edgeOffset);
-
int texCoordOffsetsByIdx[kMaxTexCoords];
int size = VertexSizeAndOffsetsByIdx(vertexLayout,
- texCoordOffsetsByIdx,
+ (NULL == texCoordOffsetsByStage) ?
+ NULL :
+ texCoordOffsetsByIdx,
colorOffset,
+ coverageOffset,
edgeOffset);
- for (int s = 0; s < kNumStages; ++s) {
- int tcIdx;
- if (StagePosAsTexCoordVertexLayoutBit(s) & vertexLayout) {
- texCoordOffsetsByStage[s] = 0;
- } else if ((tcIdx = VertexTexCoordsForStage(s, vertexLayout)) >= 0) {
- texCoordOffsetsByStage[s] = texCoordOffsetsByIdx[tcIdx];
- } else {
- texCoordOffsetsByStage[s] = -1;
+ if (NULL != texCoordOffsetsByStage) {
+ for (int s = 0; s < kNumStages; ++s) {
+ int tcIdx;
+ if (StagePosAsTexCoordVertexLayoutBit(s) & vertexLayout) {
+ texCoordOffsetsByStage[s] = 0;
+ } else if ((tcIdx = VertexTexCoordsForStage(s, vertexLayout)) >= 0) {
+ texCoordOffsetsByStage[s] = texCoordOffsetsByIdx[tcIdx];
+ } else {
+ texCoordOffsetsByStage[s] = -1;
+ }
}
}
return size;
}
+////////////////////////////////////////////////////////////////////////////////
+
bool GrDrawTarget::VertexUsesStage(int stage, GrVertexLayout vertexLayout) {
GrAssert(stage < kNumStages);
GrAssert(check_layout(vertexLayout));
@@ -241,6 +301,8 @@ int GrDrawTarget::VertexTexCoordsForStage(int stage, GrVertexLayout vertexLayout
return -1;
}
+////////////////////////////////////////////////////////////////////////////////
+
void GrDrawTarget::VertexLayoutUnitTest() {
// not necessarily exhaustive
static bool run;
@@ -286,9 +348,11 @@ void GrDrawTarget::VertexLayoutUnitTest() {
}
GrAssert(-1 == VertexEdgeOffset(tcMask));
GrAssert(-1 == VertexColorOffset(tcMask));
+ GrAssert(-1 == VertexCoverageOffset(tcMask));
#if GR_DEBUG
GrVertexLayout withColor = tcMask | kColor_VertexLayoutBit;
#endif
+ GrAssert(-1 == VertexCoverageOffset(withColor));
GrAssert(2*sizeof(GrPoint) == VertexColorOffset(withColor));
GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexSize(withColor));
#if GR_DEBUG
@@ -303,6 +367,19 @@ void GrDrawTarget::VertexLayoutUnitTest() {
GrAssert(2*sizeof(GrPoint) == VertexColorOffset(withColorAndEdge));
GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexEdgeOffset(withColorAndEdge));
GrAssert(4*sizeof(GrPoint) + sizeof(GrColor) == VertexSize(withColorAndEdge));
+ #if GR_DEBUG
+ GrVertexLayout withCoverage = tcMask | kCoverage_VertexLayoutBit;
+ #endif
+ GrAssert(-1 == VertexColorOffset(withCoverage));
+ GrAssert(2*sizeof(GrPoint) == VertexCoverageOffset(withCoverage));
+ GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexSize(withCoverage));
+ #if GR_DEBUG
+ GrVertexLayout withCoverageAndColor = tcMask | kCoverage_VertexLayoutBit |
+ kColor_VertexLayoutBit;
+ #endif
+ GrAssert(2*sizeof(GrPoint) == VertexColorOffset(withCoverageAndColor));
+ GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexCoverageOffset(withCoverageAndColor));
+ GrAssert(2*sizeof(GrPoint) + 2 * sizeof(GrColor) == VertexSize(withCoverageAndColor));
}
GrAssert(tex_coord_idx_mask(t) == tcMask);
GrAssert(check_layout(tcMask));
@@ -310,10 +387,13 @@ void GrDrawTarget::VertexLayoutUnitTest() {
int stageOffsets[kNumStages];
int colorOffset;
int edgeOffset;
+ int coverageOffset;
int size;
- size = VertexSizeAndOffsetsByStage(tcMask, stageOffsets, &colorOffset, &edgeOffset);
+ size = VertexSizeAndOffsetsByStage(tcMask, stageOffsets, &colorOffset,
+ &coverageOffset, &edgeOffset);
GrAssert(2*sizeof(GrPoint) == size);
GrAssert(-1 == colorOffset);
+ GrAssert(-1 == coverageOffset);
GrAssert(-1 == edgeOffset);
for (int s = 0; s < kNumStages; ++s) {
GrAssert(VertexUsesStage(s, tcMask));
@@ -765,8 +845,9 @@ bool GrDrawTarget::CanTweakAlphaForCoverage(GrBlendCoeff dstCoeff) {
bool GrDrawTarget::CanDisableBlend(GrVertexLayout layout, const DrState& state) {
// If we compute a coverage value (using edge AA or a coverage stage) then
// we can't force blending off.
- if (state.fEdgeAANumEdges > 0 ||
- layout & kEdge_VertexLayoutBit) {
+ if (state.fEdgeAANumEdges > 0 ||
+ (layout & kEdge_VertexLayoutBit) ||
+ (layout & kCoverage_VertexLayoutBit)) {
return false;
}
for (int s = state.fFirstCoverageStage; s < kNumStages; ++s) {
@@ -910,14 +991,10 @@ void GrDrawTarget::SetRectVertices(const GrRect& rect,
#endif
int stageOffsets[kNumStages];
- int colorOffset;
- int edgeOffset;
- int vsize = VertexSizeAndOffsetsByStage(layout, stageOffsets,
- &colorOffset, &edgeOffset);
- GrAssert(-1 == colorOffset);
- GrAssert(-1 == edgeOffset);
-
- GrTCast<GrPoint*>(vertices)->setRectFan(rect.fLeft, rect.fTop,
+ int vsize = VertexSizeAndOffsetsByStage(layout, stageOffsets,
+ NULL, NULL, NULL);
+
+ GrTCast<GrPoint*>(vertices)->setRectFan(rect.fLeft, rect.fTop,
rect.fRight, rect.fBottom,
vsize);
if (NULL != matrix) {
@@ -926,10 +1003,10 @@ void GrDrawTarget::SetRectVertices(const GrRect& rect,
for (int i = 0; i < kNumStages; ++i) {
if (stageOffsets[i] > 0) {
- GrPoint* coords = GrTCast<GrPoint*>(GrTCast<intptr_t>(vertices) +
+ GrPoint* coords = GrTCast<GrPoint*>(GrTCast<intptr_t>(vertices) +
stageOffsets[i]);
coords->setRectFan(srcRects[i]->fLeft, srcRects[i]->fTop,
- srcRects[i]->fRight, srcRects[i]->fBottom,
+ srcRects[i]->fRight, srcRects[i]->fBottom,
vsize);
if (NULL != srcMatrices && NULL != srcMatrices[i]) {
srcMatrices[i]->mapPointsWithStride(coords, vsize, 4);
diff --git a/gpu/src/GrDrawTarget.h b/gpu/src/GrDrawTarget.h
index a1667e410f..86aa3b43ea 100644
--- a/gpu/src/GrDrawTarget.h
+++ b/gpu/src/GrDrawTarget.h
@@ -53,6 +53,7 @@ public:
bool fFSAASupport : 1;
bool fDualSourceBlendingSupport : 1;
bool fBufferLockSupport : 1;
+ bool fSupportPerVertexCoverage : 1;
int fMinRenderTargetWidth;
int fMinRenderTargetHeight;
int fMaxRenderTargetSize;
@@ -408,6 +409,12 @@ public:
void setColor(GrColor);
/**
+ * Gets the currently set color.
+ * @return the current color.
+ */
+ GrColor getColor() const { return fCurrDrawState.fColor; }
+
+ /**
* Add a color filter that can be represented by a color and a mode.
*/
void setColorFilter(GrColor, SkXfermode::Mode);
@@ -517,6 +524,61 @@ public:
GrColor getBlendConstant() const { return fCurrDrawState.fBlendConstant; }
/**
+ * Determines if blend is effectively disabled.
+ *
+ * @return true if blend can be disabled without changing the rendering
+ * result given the current state including the vertex layout specified
+ * with the vertex source.
+ */
+ bool canDisableBlend() const;
+
+ /**
+ * Color alpha and coverage are two inputs to the drawing pipeline. For some
+ * blend modes it is safe to fold the coverage into constant or per-vertex
+ * color alpha value. For other blend modes they must be handled separately.
+ * Depending on features available in the underlying 3D API this may or may
+ * not be possible.
+ *
+ * This function looks at the current blend on the draw target and the draw
+ * target's capabilities to determine whether coverage can be handled
+ * correctly.
+ */
+ bool canApplyCoverage() const;
+
+ /**
+ * Determines whether incorporating partial pixel coverage into the constant
+ * color specified by setColor or per-vertex colors will give the right
+ * blending result.
+ */
+ bool canTweakAlphaForCoverage() const {
+ return CanTweakAlphaForCoverage(fCurrDrawState.fDstBlend);
+ }
+
+ /**
+ * Determines the interpretation per-vertex edge data when the
+ * kEdge_VertexLayoutBit is set (see below). When per-vertex edges are not
+ * specified the value of this setting has no effect.
+ */
+ void setVertexEdgeType(VertexEdgeType type) {
+ fCurrDrawState.fVertexEdgeType = type;
+ }
+
+ /**
+ * Given the current draw state, vertex layout, and hw support, will HW AA
+ * lines be used (if line primitive type is drawn)? (Note that lines are
+ * always 1 pixel wide)
+ */
+ virtual bool willUseHWAALines() const = 0;
+
+ /**
+ * 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 Edge* edges, int numEdges);
+
+ /**
* Used to save and restore the GrGpu's drawing state
*/
struct SavedDrawState {
@@ -557,8 +619,9 @@ public:
* The format of vertices is represented as a bitfield of flags.
* Flags that indicate the layout of vertex data. Vertices always contain
* positions and may also contain up to kMaxTexCoords sets of 2D texture
- * coordinates and per-vertex colors. Each stage can use any of the texture
- * coordinates as its input texture coordinates or it may use the positions.
+ * coordinates, per-vertex colors, and per-vertex coverage. Each stage can
+ * use any of the texture coordinates as its input texture coordinates or it
+ * may use the positions as texture coordinates.
*
* If no texture coordinates are specified for a stage then the stage is
* disabled.
@@ -567,10 +630,11 @@ public:
* example StageTexCoordVertexLayoutBit(0, 2) and
* StagePosAsTexCoordVertexLayoutBit(0) cannot both be specified.
*
- * The order in memory is always (position, texture coord 0, ..., color)
- * with any unused fields omitted. Note that this means that if only texture
- * coordinates 1 is referenced then there is no texture coordinates 0 and
- * the order would be (position, texture coordinate 1[, color]).
+ * The order in memory is always (position, texture coord 0, ..., color,
+ * coverage) with any unused fields omitted. Note that this means that if
+ * only texture coordinates 1 is referenced then there is no texture
+ * coordinates 0 and the order would be (position, texture coordinate 1
+ * [, color][, coverage]).
*/
/**
@@ -587,61 +651,6 @@ public:
return 1 << (stage + (texCoordIdx * kNumStages));
}
- /**
- * Determines if blend is effectively disabled.
- *
- * @return true if blend can be disabled without changing the rendering
- * result given the current state including the vertex layout specified
- * with the vertex source.
- */
- bool canDisableBlend() const;
-
- /**
- * Color alpha and coverage are two inputs to the drawing pipeline. For some
- * blend modes it is safe to fold the coverage into constant or per-vertex
- * color alpha value. For other blend modes they must be handled separately.
- * Depending on features available in the underlying 3D API this may or may
- * not be possible.
- *
- * This function looks at the current blend on the draw target and the draw
- * target's capabilities to determine whether coverage can be handled
- * correctly.
- */
- bool canApplyCoverage() const;
-
- /**
- * Determines whether incorporating partial pixel coverage into the constant
- * color specified by setColor or per-vertex colors will give the right
- * blending result.
- */
- bool canTweakAlphaForCoverage() const {
- return CanTweakAlphaForCoverage(fCurrDrawState.fDstBlend);
- }
-
- /**
- * Determines the interpretation per-vertex edge data when the
- * kEdge_VertexLayoutBit is set (see below). When per-vertex edges are not
- * specified the value of this setting has no effect.
- */
- void setVertexEdgeType(VertexEdgeType type) {
- fCurrDrawState.fVertexEdgeType = type;
- }
-
- /**
- * Given the current draw state, vertex layout, and hw support, will HW AA
- * lines be used (if line primitive type is drawn)? (Note that lines are
- * always 1 pixel wide)
- */
- virtual bool willUseHWAALines() const = 0;
-
- /**
- * 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 Edge* edges, int numEdges);
-
private:
static const int TEX_COORD_BIT_CNT = kNumStages*kMaxTexCoords;
public:
@@ -658,6 +667,7 @@ public:
GrAssert(stage < kNumStages);
return (1 << (TEX_COORD_BIT_CNT + stage));
}
+
private:
static const int STAGE_BIT_CNT = TEX_COORD_BIT_CNT + kNumStages;
@@ -667,14 +677,15 @@ public:
* Additional Bits that can be specified in GrVertexLayout.
*/
enum VertexLayoutBits {
- /* vertices have colors */
+ /* vertices have colors (GrColor) */
kColor_VertexLayoutBit = 1 << (STAGE_BIT_CNT + 0),
-
+ /* vertices have coverage (GrColor where only the alpha chan is used */
+ kCoverage_VertexLayoutBit = 1 << (STAGE_BIT_CNT + 1),
/* Use text vertices. (Pos and tex coords may be a different type for
text [GrGpuTextVertex vs GrPoint].) */
- kTextFormat_VertexLayoutBit = 1 << (STAGE_BIT_CNT + 1),
+ kTextFormat_VertexLayoutBit = 1 << (STAGE_BIT_CNT + 2),
- kEdge_VertexLayoutBit = 1 << (STAGE_BIT_CNT + 2),
+ kEdge_VertexLayoutBit = 1 << (STAGE_BIT_CNT + 3),
// for below assert
kDummyVertexLayoutBit,
kHighVertexLayoutBit = kDummyVertexLayoutBit - 1
@@ -1121,6 +1132,13 @@ public:
*/
static int VertexColorOffset(GrVertexLayout vertexLayout);
+ /**
+ * Helper function to compute the offset of the coverage in a vertex
+ * @return offset of coverage in vertex layout or -1 if the
+ * layout has no coverage.
+ */
+ static int VertexCoverageOffset(GrVertexLayout vertexLayout);
+
/**
* Helper function to compute the offset of the edge pts in a vertex
* @return offset of edge in vertex layout or -1 if the
@@ -1162,12 +1180,24 @@ public:
* @param vertexLayout the layout to query
* @param texCoordOffsetsByIdx after return it is the offset of each
* tex coord index in the vertex or -1 if
- * index isn't used.
+ * index isn't used. (optional)
+ * @param colorOffset after return it is the offset of the
+ * color field in each vertex, or -1 if
+ * there aren't per-vertex colors. (optional)
+ * @param coverageOffset after return it is the offset of the
+ * coverage field in each vertex, or -1 if
+ * there aren't per-vertex coeverages.
+ * (optional)
+ * @param edgeOffset after return it is the offset of the
+ * edge eq field in each vertex, or -1 if
+ * there aren't per-vertex edge equations.
+ * (optional)
* @return size of a single vertex
*/
static int VertexSizeAndOffsetsByIdx(GrVertexLayout vertexLayout,
int texCoordOffsetsByIdx[kMaxTexCoords],
int *colorOffset,
+ int *coverageOffset,
int* edgeOffset);
/**
@@ -1180,12 +1210,25 @@ public:
* @param vertexLayout the layout to query
* @param texCoordOffsetsByStage after return it is the offset of each
* tex coord index in the vertex or -1 if
- * index isn't used.
+ * index isn't used. (optional)
+ * @param colorOffset after return it is the offset of the
+ * color field in each vertex, or -1 if
+ * there aren't per-vertex colors.
+ * (optional)
+ * @param coverageOffset after return it is the offset of the
+ * coverage field in each vertex, or -1 if
+ * there aren't per-vertex coeverages.
+ * (optional)
+ * @param edgeOffset after return it is the offset of the
+ * edge eq field in each vertex, or -1 if
+ * there aren't per-vertex edge equations.
+ * (optional)
* @return size of a single vertex
*/
static int VertexSizeAndOffsetsByStage(GrVertexLayout vertexLayout,
int texCoordOffsetsByStage[kNumStages],
int *colorOffset,
+ int *coverageOffset,
int* edgeOffset);
/**
diff --git a/gpu/src/GrGLProgram.cpp b/gpu/src/GrGLProgram.cpp
index cbe2f42486..4b97fab14c 100644
--- a/gpu/src/GrGLProgram.cpp
+++ b/gpu/src/GrGLProgram.cpp
@@ -81,6 +81,7 @@ struct ShaderCodeSegments {
#define POS_ATTR_NAME "aPosition"
#define COL_ATTR_NAME "aColor"
+#define COV_ATTR_NAME "aCoverage"
#define EDGE_ATTR_NAME "aEdge"
#define COL_UNI_NAME "uColor"
#define EDGES_UNI_NAME "uEdges"
@@ -751,6 +752,23 @@ bool GrGLProgram::genProgram(const GrGLInterface* gl,
// get edge AA coverage and use it as inCoverage to first coverage stage
this->genEdgeCoverage(gl, layout, programData, &inCoverage, &segments);
+ // include explicit per-vertex coverage if we have it
+ if (GrDrawTarget::kCoverage_VertexLayoutBit & layout) {
+ segments.fVSAttrs.push_back().set(GrGLShaderVar::kFloat_Type,
+ COV_ATTR_NAME);
+ const char *vsName, *fsName;
+ append_varying(GrGLShaderVar::kFloat_Type, "Coverage",
+ &segments, &vsName, &fsName);
+ segments.fVSCode.appendf("\t%s = " COV_ATTR_NAME ";\n", vsName);
+ if (inCoverage.size()) {
+ segments.fFSCode.appendf("\tfloat edgeAndAttrCov = %s * %s;\n",
+ fsName, inCoverage.c_str());
+ inCoverage = "edgeAndAttrCov";
+ } else {
+ inCoverage = fsName;
+ }
+ }
+
GrStringBuilder outCoverage;
const int& startStage = fProgramDesc.fFirstCoverageStage;
for (int s = startStage; s < GrDrawTarget::kNumStages; ++s) {
@@ -1100,6 +1118,8 @@ bool GrGLProgram::bindOutputsAttribsAndLinkProgram(
GR_GL_CALL(gl, BindAttribLocation(progID, ColorAttributeIdx(),
COL_ATTR_NAME));
+ GR_GL_CALL(gl, BindAttribLocation(progID, CoverageAttributeIdx(),
+ COV_ATTR_NAME));
GR_GL_CALL(gl, BindAttribLocation(progID, EdgeAttributeIdx(),
EDGE_ATTR_NAME));
diff --git a/gpu/src/GrGLProgram.h b/gpu/src/GrGLProgram.h
index a79f877223..197da5d61c 100644
--- a/gpu/src/GrGLProgram.h
+++ b/gpu/src/GrGLProgram.h
@@ -66,7 +66,10 @@ public:
static int PositionAttributeIdx() { return 0; }
static int TexCoordAttributeIdx(int tcIdx) { return 1 + tcIdx; }
static int ColorAttributeIdx() { return 1 + GrDrawTarget::kMaxTexCoords; }
- static int EdgeAttributeIdx() { return 2 + GrDrawTarget::kMaxTexCoords; }
+ static int CoverageAttributeIdx() {
+ return 2 + GrDrawTarget::kMaxTexCoords;
+ }
+ static int EdgeAttributeIdx() { return 3 + GrDrawTarget::kMaxTexCoords; }
static int ViewMatrixAttributeIdx() {
return 2 + GrDrawTarget::kMaxTexCoords;
diff --git a/gpu/src/GrGpuGLFixed.cpp b/gpu/src/GrGpuGLFixed.cpp
index 195ca32502..c9d5844b4f 100644
--- a/gpu/src/GrGpuGLFixed.cpp
+++ b/gpu/src/GrGpuGLFixed.cpp
@@ -272,23 +272,29 @@ void GrGpuGLFixed::setupGeometry(int* startVertex,
int indexCount) {
int newColorOffset;
+ int newCoverageOffset;
int newTexCoordOffsets[kNumStages];
int newEdgeOffset;
GrGLsizei newStride = VertexSizeAndOffsetsByStage(this->getGeomSrc().fVertexLayout,
newTexCoordOffsets,
&newColorOffset,
+ &newCoverageOffset,
&newEdgeOffset);
GrAssert(-1 == newEdgeOffset); // not supported by fixed pipe
+ GrAssert(-1 == newCoverageOffset); // not supported by fixed pipe
int oldColorOffset;
+ int oldCoverageOffset;
int oldTexCoordOffsets[kNumStages];
int oldEdgeOffset;
GrGLsizei oldStride = VertexSizeAndOffsetsByStage(fHWGeometryState.fVertexLayout,
oldTexCoordOffsets,
&oldColorOffset,
+ &oldCoverageOffset,
&oldEdgeOffset);
GrAssert(-1 == oldEdgeOffset);
+ GrAssert(-1 == oldCoverageOffset);
bool indexed = NULL != startIndex;
diff --git a/gpu/src/GrGpuGLShaders.cpp b/gpu/src/GrGpuGLShaders.cpp
index 80f0268b02..3ca4346b88 100644
--- a/gpu/src/GrGpuGLShaders.cpp
+++ b/gpu/src/GrGpuGLShaders.cpp
@@ -219,6 +219,10 @@ bool GrGpuGLShaders::programUnitTest() {
idx = (int)(random.nextF() * (kNumStages+1));
pdesc.fFirstCoverageStage = idx;
+ pdesc.fVertexLayout |= (random.nextF() > .5f) ?
+ GrDrawTarget::kCoverage_VertexLayoutBit :
+ 0;
+
#if GR_GL_EXPERIMENTAL_GS
pdesc.fExperimentalGS = this->getCaps().fGeometryShaderSupport &&
random.nextF() > .5f;
@@ -238,8 +242,8 @@ bool GrGpuGLShaders::programUnitTest() {
}
pdesc.fEdgeAANumEdges = 0;
} else {
- pdesc.fEdgeAANumEdges = SkToS8(1 + random.nextF() *
- this->getMaxEdges());
+ pdesc.fEdgeAANumEdges = static_cast<int>(1 + random.nextF() *
+ this->getMaxEdges());
pdesc.fEdgeAAConcave = random.nextF() > .5f;
}
} else {
@@ -312,6 +316,7 @@ GrGpuGLShaders::GrGpuGLShaders(const GrGLInterface* gl)
// Enable supported shader-releated caps
fCaps.fShaderSupport = true;
+ fCaps.fSupportPerVertexCoverage = true;
if (kDesktop_GrGLBinding == this->glBinding()) {
fCaps.fDualSourceBlendingSupport =
this->glVersion() >= GR_GL_VER(3,3) ||
@@ -700,6 +705,7 @@ void GrGpuGLShaders::setupGeometry(int* startVertex,
int indexCount) {
int newColorOffset;
+ int newCoverageOffset;
int newTexCoordOffsets[kMaxTexCoords];
int newEdgeOffset;
@@ -707,8 +713,10 @@ void GrGpuGLShaders::setupGeometry(int* startVertex,
this->getGeomSrc().fVertexLayout,
newTexCoordOffsets,
&newColorOffset,
+ &newCoverageOffset,
&newEdgeOffset);
int oldColorOffset;
+ int oldCoverageOffset;
int oldTexCoordOffsets[kMaxTexCoords];
int oldEdgeOffset;
@@ -716,6 +724,7 @@ void GrGpuGLShaders::setupGeometry(int* startVertex,
fHWGeometryState.fVertexLayout,
oldTexCoordOffsets,
&oldColorOffset,
+ &oldCoverageOffset,
&oldEdgeOffset);
bool indexed = NULL != startIndex;
@@ -792,6 +801,23 @@ void GrGpuGLShaders::setupGeometry(int* startVertex,
GL_CALL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
}
+ if (newCoverageOffset > 0) {
+ // bind just alpha channel.
+ GrGLvoid* coverageOffset = (int8_t*)(vertexOffset + newCoverageOffset +
+ GrColor_INDEX_A);
+ int idx = GrGLProgram::CoverageAttributeIdx();
+ if (oldCoverageOffset <= 0) {
+ GL_CALL(EnableVertexAttribArray(idx));
+ GL_CALL(VertexAttribPointer(idx, 1, GR_GL_UNSIGNED_BYTE,
+ true, newStride, coverageOffset));
+ } else if (allOffsetsChange || newCoverageOffset != oldCoverageOffset) {
+ GL_CALL(VertexAttribPointer(idx, 1, GR_GL_UNSIGNED_BYTE,
+ true, newStride, coverageOffset));
+ }
+ } else if (oldCoverageOffset > 0) {
+ GL_CALL(DisableVertexAttribArray(GrGLProgram::CoverageAttributeIdx()));
+ }
+
if (newEdgeOffset > 0) {
GrGLvoid* edgeOffset = (int8_t*)(vertexOffset + newEdgeOffset);
int idx = GrGLProgram::EdgeAttributeIdx();
@@ -954,13 +980,30 @@ void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
desc.fExperimentalGS = this->getCaps().fGeometryShaderSupport;
#endif
- // use canonical value when coverage/color distinction won't affect
- // generated code to prevent duplicate programs.
+ // we want to avoid generating programs with different "first cov stage"
+ // values when they would compute the same result.
+ // We set field in the desc to kNumStages when either there are no
+ // coverage stages or the distinction between coverage and color is
+ // immaterial.
+ int firstCoverageStage = kNumStages;
desc.fFirstCoverageStage = kNumStages;
- if (fCurrDrawState.fFirstCoverageStage <= lastEnabledStage) {
+ bool hasCoverage = fCurrDrawState.fFirstCoverageStage <= lastEnabledStage;
+ if (hasCoverage) {
+ firstCoverageStage = fCurrDrawState.fFirstCoverageStage;
+ }
+
+ // other coverage inputs
+ if (!hasCoverage) {
+ hasCoverage =
+ desc.fEdgeAANumEdges ||
+ (desc.fVertexLayout & GrDrawTarget::kCoverage_VertexLayoutBit) ||
+ (desc.fVertexLayout & GrDrawTarget::kEdge_VertexLayoutBit);
+ }
+
+ if (hasCoverage) {
// color filter is applied between color/coverage computation
if (SkXfermode::kDst_Mode != desc.fColorFilterXfermode) {
- desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
+ desc.fFirstCoverageStage = firstCoverageStage;
}
// We could consider cases where the final color is solid (0xff alpha)
@@ -972,17 +1015,17 @@ void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
if (kZero_BlendCoeff == fCurrDrawState.fDstBlend) {
// write the coverage value to second color
desc.fDualSrcOutput = ProgramDesc::kCoverage_DualSrcOutput;
- desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
+ desc.fFirstCoverageStage = firstCoverageStage;
} else if (kSA_BlendCoeff == fCurrDrawState.fDstBlend) {
// SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
// cover
desc.fDualSrcOutput = ProgramDesc::kCoverageISA_DualSrcOutput;
- desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
+ desc.fFirstCoverageStage = firstCoverageStage;
} else if (kSC_BlendCoeff == fCurrDrawState.fDstBlend) {
// SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
// cover
desc.fDualSrcOutput = ProgramDesc::kCoverageISC_DualSrcOutput;
- desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
+ desc.fFirstCoverageStage = firstCoverageStage;
}
}
}