aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-10-10 14:08:47 +0000
committerGravatar bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-10-10 14:08:47 +0000
commita31082685544d0ae4c0b203d7f5ff960640ed8df (patch)
treea7d44dbf5cb6cd0caf5c7e124f650063a8c0df0f
parentf12449b5d2867ca653aa53ac58fc1148e7f0b636 (diff)
Add per-vertex coverage field, use in AA rects when alpha tweak is not valid, add relevant sample/gm
Review URL: http://codereview.appspot.com/5181044/ git-svn-id: http://skia.googlecode.com/svn/trunk@2440 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r--gm/aarectmodes.cpp157
-rw-r--r--gpu/include/GrContext.h8
-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
-rw-r--r--gyp/SampleApp.gyp1
-rw-r--r--gyp/gm.gyp1
-rw-r--r--samplecode/SampleAARectModes.cpp152
12 files changed, 687 insertions, 154 deletions
diff --git a/gm/aarectmodes.cpp b/gm/aarectmodes.cpp
new file mode 100644
index 0000000000..ffb267d892
--- /dev/null
+++ b/gm/aarectmodes.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gm.h"
+#include "SkCanvas.h"
+#include "SkColorPriv.h"
+#include "SkShader.h"
+
+static SkCanvas* create_canvas(int w, int h) {
+ SkBitmap bm;
+ bm.setConfig(SkBitmap::kARGB_8888_Config, w, h);
+ bm.allocPixels();
+ bm.eraseColor(0);
+ return new SkCanvas(bm);
+}
+
+static const SkBitmap& extract_bitmap(SkCanvas* canvas) {
+ return canvas->getDevice()->accessBitmap(false);
+}
+
+static const struct {
+ SkXfermode::Mode fMode;
+ const char* fLabel;
+} gModes[] = {
+ { SkXfermode::kClear_Mode, "Clear" },
+ { SkXfermode::kSrc_Mode, "Src" },
+ { SkXfermode::kDst_Mode, "Dst" },
+ { SkXfermode::kSrcOver_Mode, "SrcOver" },
+ { SkXfermode::kDstOver_Mode, "DstOver" },
+ { SkXfermode::kSrcIn_Mode, "SrcIn" },
+ { SkXfermode::kDstIn_Mode, "DstIn" },
+ { SkXfermode::kSrcOut_Mode, "SrcOut" },
+ { SkXfermode::kDstOut_Mode, "DstOut" },
+ { SkXfermode::kSrcATop_Mode, "SrcATop" },
+ { SkXfermode::kDstATop_Mode, "DstATop" },
+ { SkXfermode::kXor_Mode, "Xor" },
+};
+
+const int gWidth = 64;
+const int gHeight = 64;
+const SkScalar W = SkIntToScalar(gWidth);
+const SkScalar H = SkIntToScalar(gHeight);
+
+static SkScalar drawCell(SkCanvas* canvas, SkXfermode* mode,
+ SkAlpha a0, SkAlpha a1) {
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+
+ SkRect r = SkRect::MakeWH(W, H);
+ r.inset(W/10, H/10);
+
+ paint.setColor(SK_ColorBLUE);
+ paint.setAlpha(a0);
+ canvas->drawOval(r, paint);
+
+ paint.setColor(SK_ColorRED);
+ paint.setAlpha(a1);
+ paint.setXfermode(mode);
+
+ SkScalar offset = SK_Scalar1 / 3;
+ SkRect rect = SkRect::MakeXYWH(W / 4 + offset,
+ H / 4 + offset,
+ W / 2, H / 2);
+ canvas->drawRect(rect, paint);
+
+ return H;
+}
+
+static SkShader* make_bg_shader() {
+ SkBitmap bm;
+ bm.setConfig(SkBitmap::kARGB_8888_Config, 2, 2);
+ bm.allocPixels();
+ *bm.getAddr32(0, 0) = *bm.getAddr32(1, 1) = 0xFFFFFFFF;
+ *bm.getAddr32(1, 0) = *bm.getAddr32(0, 1) = SkPackARGB32(0xFF, 0xCC,
+ 0xCC, 0xCC);
+
+ SkShader* s = SkShader::CreateBitmapShader(bm,
+ SkShader::kRepeat_TileMode,
+ SkShader::kRepeat_TileMode);
+
+ SkMatrix m;
+ m.setScale(SkIntToScalar(6), SkIntToScalar(6));
+ s->setLocalMatrix(m);
+ return s;
+}
+
+namespace skiagm {
+
+ class AARectModesGM : public GM {
+ SkPaint fBGPaint;
+ public:
+ AARectModesGM () {
+ fBGPaint.setShader(make_bg_shader())->unref();
+ }
+
+ protected:
+
+ virtual SkString onShortName() {
+ return SkString("aarectmodes");
+ }
+
+ virtual SkISize onISize() { return make_isize(640, 480); }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ canvas->drawColor(SK_ColorWHITE);
+
+ const SkRect bounds = SkRect::MakeWH(W, H);
+ static const SkAlpha gAlphaValue[] = { 0xFF, 0x88, 0x88 };
+
+ canvas->translate(SkIntToScalar(4), SkIntToScalar(4));
+
+ for (int alpha = 0; alpha < 4; ++alpha) {
+ canvas->save();
+ canvas->save();
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); ++i) {
+ if (6 == i) {
+ canvas->restore();
+ canvas->translate(W * 5, 0);
+ canvas->save();
+ }
+ SkXfermode* mode = SkXfermode::Create(gModes[i].fMode);
+
+ canvas->drawRect(bounds, fBGPaint);
+ canvas->saveLayer(&bounds, NULL);
+ SkScalar dy = drawCell(canvas, mode,
+ gAlphaValue[alpha & 1],
+ gAlphaValue[alpha & 2]);
+ canvas->restore();
+
+ canvas->translate(0, dy * 5 / 4);
+ SkSafeUnref(mode);
+ }
+ canvas->restore();
+ canvas->restore();
+ canvas->translate(W * 5 / 4, 0);
+ }
+ }
+
+ // disable pdf for now, since it crashes on mac
+ virtual uint32_t onGetFlags() const { return kSkipPDF_Flag; }
+
+ private:
+ typedef GM INHERITED;
+ };
+
+//////////////////////////////////////////////////////////////////////////////
+
+ static GM* MyFactory(void*) { return new AARectModesGM; }
+ static GMRegistry reg(MyFactory);
+
+}
+
diff --git a/gpu/include/GrContext.h b/gpu/include/GrContext.h
index eeb96ccc32..4a1f1da8c4 100644
--- a/gpu/include/GrContext.h
+++ b/gpu/include/GrContext.h
@@ -563,13 +563,13 @@ private:
GrContext(GrGpu* gpu);
void fillAARect(GrDrawTarget* target,
- const GrPaint& paint,
- const GrRect& devRect);
+ const GrRect& devRect,
+ bool useVertexCoverage);
void strokeAARect(GrDrawTarget* target,
- const GrPaint& paint,
const GrRect& devRect,
- const GrVec& devStrokeSize);
+ const GrVec& devStrokeSize,
+ bool useVertexCoverage);
inline int aaFillRectIndexCount() const;
GrIndexBuffer* aaFillRectIndexBuffer();
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;
}
}
}
diff --git a/gyp/SampleApp.gyp b/gyp/SampleApp.gyp
index dfd1e4c352..a3ffd65f47 100644
--- a/gyp/SampleApp.gyp
+++ b/gyp/SampleApp.gyp
@@ -35,6 +35,7 @@
'../samplecode/OverView.cpp',
'../samplecode/Sample2PtRadial.cpp',
'../samplecode/SampleAARects.cpp',
+ '../samplecode/SampleAARectModes.cpp',
'../samplecode/SampleAll.cpp',
'../samplecode/SampleAnimator.cpp',
'../samplecode/SampleApp.cpp',
diff --git a/gyp/gm.gyp b/gyp/gm.gyp
index fc43221947..575cb8d00f 100644
--- a/gyp/gm.gyp
+++ b/gyp/gm.gyp
@@ -9,6 +9,7 @@
'target_name': 'gm',
'type': 'executable',
'sources': [
+ '../gm/aarectmodes.cpp',
'../gm/bitmapfilters.cpp',
'../gm/bitmapscroll.cpp',
'../gm/blurs.cpp',
diff --git a/samplecode/SampleAARectModes.cpp b/samplecode/SampleAARectModes.cpp
new file mode 100644
index 0000000000..7b9e7d5eb3
--- /dev/null
+++ b/samplecode/SampleAARectModes.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkDevice.h"
+#include "SkColorPriv.h"
+#include "SkShader.h"
+
+static SkCanvas* create_canvas(int w, int h) {
+ SkBitmap bm;
+ bm.setConfig(SkBitmap::kARGB_8888_Config, w, h);
+ bm.allocPixels();
+ bm.eraseColor(0);
+ return new SkCanvas(bm);
+}
+
+static const SkBitmap& extract_bitmap(SkCanvas* canvas) {
+ return canvas->getDevice()->accessBitmap(false);
+}
+
+static const struct {
+ SkXfermode::Mode fMode;
+ const char* fLabel;
+} gModes[] = {
+ { SkXfermode::kClear_Mode, "Clear" },
+ { SkXfermode::kSrc_Mode, "Src" },
+ { SkXfermode::kDst_Mode, "Dst" },
+ { SkXfermode::kSrcOver_Mode, "SrcOver" },
+ { SkXfermode::kDstOver_Mode, "DstOver" },
+ { SkXfermode::kSrcIn_Mode, "SrcIn" },
+ { SkXfermode::kDstIn_Mode, "DstIn" },
+ { SkXfermode::kSrcOut_Mode, "SrcOut" },
+ { SkXfermode::kDstOut_Mode, "DstOut" },
+ { SkXfermode::kSrcATop_Mode, "SrcATop" },
+ { SkXfermode::kDstATop_Mode, "DstATop" },
+ { SkXfermode::kXor_Mode, "Xor" },
+};
+
+const int gWidth = 64;
+const int gHeight = 64;
+const SkScalar W = SkIntToScalar(gWidth);
+const SkScalar H = SkIntToScalar(gHeight);
+
+static SkScalar drawCell(SkCanvas* canvas, SkXfermode* mode,
+ SkAlpha a0, SkAlpha a1) {
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+
+ SkRect r = SkRect::MakeWH(W, H);
+ r.inset(W/10, H/10);
+
+ paint.setColor(SK_ColorBLUE);
+ paint.setAlpha(a0);
+ canvas->drawOval(r, paint);
+
+ paint.setColor(SK_ColorRED);
+ paint.setAlpha(a1);
+ paint.setXfermode(mode);
+
+ SkScalar offset = SK_Scalar1 / 3;
+ SkRect rect = SkRect::MakeXYWH(W / 4 + offset,
+ H / 4 + offset,
+ W / 2, H / 2);
+ canvas->drawRect(rect, paint);
+
+ return H;
+}
+
+static SkShader* make_bg_shader() {
+ SkBitmap bm;
+ bm.setConfig(SkBitmap::kARGB_8888_Config, 2, 2);
+ bm.allocPixels();
+ *bm.getAddr32(0, 0) = *bm.getAddr32(1, 1) = 0xFFFFFFFF;
+ *bm.getAddr32(1, 0) = *bm.getAddr32(0, 1) = SkPackARGB32(0xFF, 0xCC,
+ 0xCC, 0xCC);
+
+ SkShader* s = SkShader::CreateBitmapShader(bm,
+ SkShader::kRepeat_TileMode,
+ SkShader::kRepeat_TileMode);
+
+ SkMatrix m;
+ m.setScale(SkIntToScalar(6), SkIntToScalar(6));
+ s->setLocalMatrix(m);
+ return s;
+}
+
+class AARectsModesView : public SampleView {
+ SkPaint fBGPaint;
+public:
+ AARectsModesView () {
+ fBGPaint.setShader(make_bg_shader())->unref();
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "AARectsModes");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ const SkRect bounds = SkRect::MakeWH(W, H);
+ static const SkAlpha gAlphaValue[] = { 0xFF, 0x88, 0x88 };
+
+ canvas->translate(SkIntToScalar(4), SkIntToScalar(4));
+
+ for (int alpha = 0; alpha < 4; ++alpha) {
+ canvas->save();
+ canvas->save();
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); ++i) {
+ if (6 == i) {
+ canvas->restore();
+ canvas->translate(W * 5, 0);
+ canvas->save();
+ }
+ SkXfermode* mode = SkXfermode::Create(gModes[i].fMode);
+
+ canvas->drawRect(bounds, fBGPaint);
+ canvas->saveLayer(&bounds, NULL);
+ SkScalar dy = drawCell(canvas, mode,
+ gAlphaValue[alpha & 1],
+ gAlphaValue[alpha & 2]);
+ canvas->restore();
+
+ canvas->translate(0, dy * 5 / 4);
+ SkSafeUnref(mode);
+ }
+ canvas->restore();
+ canvas->restore();
+ canvas->translate(W * 5 / 4, 0);
+ }
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new AARectsModesView; }
+static SkViewRegister reg(MyFactory);
+