aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gyp/gpu.gypi2
-rw-r--r--include/gpu/GrContext.h3
-rw-r--r--include/gpu/GrEffectStage.h39
-rw-r--r--src/gpu/GrContext.cpp314
-rw-r--r--src/gpu/GrDrawState.h14
-rw-r--r--src/gpu/effects/GrCircleEdgeEffect.cpp87
-rw-r--r--src/gpu/effects/GrCircleEdgeEffect.h65
-rw-r--r--src/gpu/effects/GrEllipseEdgeEffect.cpp51
-rw-r--r--src/gpu/effects/GrEllipseEdgeEffect.h24
-rw-r--r--src/gpu/gl/GrGLProgram.cpp34
-rw-r--r--tests/GLProgramsTest.cpp2
11 files changed, 472 insertions, 163 deletions
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi
index d964f20a07..6b039d0636 100644
--- a/gyp/gpu.gypi
+++ b/gyp/gpu.gypi
@@ -122,6 +122,8 @@
'<(skia_src_path)/gpu/gr_unittests.cpp',
'<(skia_src_path)/gpu/effects/Gr1DKernelEffect.h',
+ '<(skia_src_path)/gpu/effects/GrCircleEdgeEffect.cpp',
+ '<(skia_src_path)/gpu/effects/GrCircleEdgeEffect.h',
'<(skia_src_path)/gpu/effects/GrConfigConversionEffect.cpp',
'<(skia_src_path)/gpu/effects/GrConfigConversionEffect.h',
'<(skia_src_path)/gpu/effects/GrConvolutionEffect.cpp',
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index c5572ac3a7..79edd0b11b 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -894,7 +894,8 @@ private:
void internalDrawPath(const GrPaint& paint, const SkPath& path, const SkStrokeRec& stroke);
void internalDrawOval(const GrPaint& paint, const GrRect& oval, const SkStrokeRec& stroke);
- bool canDrawOval(const GrPaint& paint, const GrRect& oval, const SkStrokeRec& stroke) const;
+ void internalDrawCircle(const GrPaint& paint, const GrRect& circle, const SkStrokeRec& stroke);
+ bool canDrawOval(const GrPaint& paint, const GrRect& oval, bool* isCircle) const;
GrTexture* createResizedTexture(const GrTextureDesc& desc,
const GrCacheID& cacheID,
diff --git a/include/gpu/GrEffectStage.h b/include/gpu/GrEffectStage.h
index ff118c384c..cd9a0910fc 100644
--- a/include/gpu/GrEffectStage.h
+++ b/include/gpu/GrEffectStage.h
@@ -116,7 +116,8 @@ public:
stage.fEffectRef->get()->incDeferredRefCounts();
fEffect = stage.fEffectRef->get();
fCoordChangeMatrix = stage.fCoordChangeMatrix;
- fVertexAttribIndices = stage.fVertexAttribIndices;
+ fVertexAttribIndices[0] = stage.fVertexAttribIndices[0];
+ fVertexAttribIndices[1] = stage.fVertexAttribIndices[1];
}
SkDEBUGCODE(fInitialized = true;)
}
@@ -127,7 +128,8 @@ public:
if (NULL != fEffect) {
stage->fEffectRef = GrEffect::CreateEffectRef(fEffect);
stage->fCoordChangeMatrix = fCoordChangeMatrix;
- stage->fVertexAttribIndices = fVertexAttribIndices;
+ stage->fVertexAttribIndices[0] = fVertexAttribIndices[0];
+ stage->fVertexAttribIndices[1] = fVertexAttribIndices[1];
} else {
stage->fEffectRef = NULL;
}
@@ -141,7 +143,8 @@ public:
return false;
}
- if (fVertexAttribIndices != stage.fVertexAttribIndices) {
+ if (fVertexAttribIndices[0] != stage.fVertexAttribIndices[0]
+ || fVertexAttribIndices[1] != stage.fVertexAttribIndices[1]) {
return false;
}
@@ -155,7 +158,8 @@ public:
private:
const GrEffect* fEffect;
SkMatrix fCoordChangeMatrix;
- SkSTArray<GrEffect::kMaxVertexAttribs, int, true> fVertexAttribIndices;
+ int fVertexAttribIndices[2];
+ int fVertexAttribCount;
SkDEBUGCODE(bool fInitialized;)
};
@@ -169,28 +173,37 @@ public:
GrSafeSetNull(fEffectRef);
}
- const GrEffectRef* setEffect(const GrEffectRef* EffectRef, const int* attribIndices = NULL) {
+ const GrEffectRef* setEffect(const GrEffectRef* EffectRef) {
GrAssert(0 == fSavedCoordChangeCnt);
GrSafeAssign(fEffectRef, EffectRef);
fCoordChangeMatrix.reset();
- fVertexAttribIndices.reset();
- int numVertexAttribs = (EffectRef == NULL) ? 0 : EffectRef->get()->numVertexAttribs();
- GrAssert(numVertexAttribs == 0 || attribIndices != NULL);
- fVertexAttribIndices.push_back_n(numVertexAttribs, attribIndices);
-
+ fVertexAttribIndices[0] = -1;
+ fVertexAttribIndices[1] = -1;
+
return EffectRef;
}
+ const GrEffectRef* setEffect(const GrEffectRef* EffectRef, int attr0, int attr1 = -1) {
+ GrAssert(0 == fSavedCoordChangeCnt);
+ GrSafeAssign(fEffectRef, EffectRef);
+ fCoordChangeMatrix.reset();
+
+ fVertexAttribIndices[0] = attr0;
+ fVertexAttribIndices[1] = attr1;
+
+ return EffectRef;
+ }
+
const GrEffectRef* getEffect() const { return fEffectRef; }
- const int* getVertexAttribIndices() const { return fVertexAttribIndices.begin(); }
- int getVertexAttribIndexCount() const { return fVertexAttribIndices.count(); }
+ const int* getVertexAttribIndices() const { return fVertexAttribIndices; }
+ int getVertexAttribIndexCount() const { return fEffectRef->get()->numVertexAttribs(); }
private:
SkMatrix fCoordChangeMatrix;
const GrEffectRef* fEffectRef;
- SkSTArray<2, int, true> fVertexAttribIndices;
+ int fVertexAttribIndices[2];
GR_DEBUGCODE(mutable int fSavedCoordChangeCnt;)
};
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index b719ec5a53..cf74c8ed60 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -12,6 +12,7 @@
#include "effects/GrConvolutionEffect.h"
#include "effects/GrSingleTextureEffect.h"
#include "effects/GrConfigConversionEffect.h"
+#include "effects/GrCircleEdgeEffect.h"
#include "effects/GrEllipseEdgeEffect.h"
#include "GrBufferAllocPool.h"
@@ -36,7 +37,8 @@ SK_DEFINE_INST_COUNT(GrDrawState)
// It can be useful to set this to false to test whether a bug is caused by using the
// InOrderDrawBuffer, to compare performance of using/not using InOrderDrawBuffer, or to make
// debugging simpler.
-SK_CONF_DECLARE(bool, c_Defer, "gpu.deferContext", true, "Defers rendering in GrContext via GrInOrderDrawBuffer.");
+SK_CONF_DECLARE(bool, c_Defer, "gpu.deferContext", true,
+ "Defers rendering in GrContext via GrInOrderDrawBuffer.");
#define BUFFERED_DRAW (c_Defer ? kYes_BufferedDraw : kNo_BufferedDraw)
@@ -358,7 +360,8 @@ GrTexture* GrContext::createResizedTexture(const GrTextureDesc& desc,
{kVec2f_GrVertexAttribType, 0},
{kVec2f_GrVertexAttribType, sizeof(GrPoint)}
};
- static const GrAttribBindings kAttribBindings = GrDrawState::ExplicitTexCoordAttribBindingsBit(0);
+ static const GrAttribBindings kAttribBindings =
+ GrDrawState::ExplicitTexCoordAttribBindingsBit(0);
drawState->setAttribBindings(kAttribBindings);
drawState->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs));
drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0);
@@ -389,7 +392,8 @@ GrTexture* GrContext::createResizedTexture(const GrTextureDesc& desc,
size_t stretchedRowBytes = rtDesc.fWidth * bpp;
- SkDEBUGCODE(GrTexture* texture = )fGpu->createTexture(rtDesc, stretchedPixels.get(), stretchedRowBytes);
+ SkDEBUGCODE(GrTexture* texture = )fGpu->createTexture(rtDesc, stretchedPixels.get(),
+ stretchedRowBytes);
GrAssert(NULL != texture);
}
@@ -999,6 +1003,15 @@ struct CircleVertex {
SkScalar fInnerRadius;
};
+struct EllipseVertex {
+ GrPoint fPos;
+ GrPoint fCenter;
+ SkScalar fOuterXRadius;
+ SkScalar fOuterXYRatio;
+ SkScalar fInnerXRadius;
+ SkScalar fInnerXYRatio;
+};
+
inline bool circleStaysCircle(const SkMatrix& m) {
return m.isSimilarity();
}
@@ -1009,64 +1022,59 @@ void GrContext::drawOval(const GrPaint& paint,
const GrRect& oval,
const SkStrokeRec& stroke) {
- if (!canDrawOval(paint, oval, stroke)) {
+ bool isCircle;
+ if (!canDrawOval(paint, oval, &isCircle)) {
SkPath path;
path.addOval(oval);
this->drawPath(paint, path, stroke);
return;
}
- internalDrawOval(paint, oval, stroke);
+ if (isCircle) {
+ this->internalDrawCircle(paint, oval, stroke);
+ } else {
+ this->internalDrawOval(paint, oval, stroke);
+ }
}
-bool GrContext::canDrawOval(const GrPaint& paint, const GrRect& oval, const SkStrokeRec& stroke) const {
+bool GrContext::canDrawOval(const GrPaint& paint, const GrRect& oval, bool* isCircle) const {
+ GrAssert(isCircle != NULL);
if (!paint.isAntiAlias()) {
return false;
}
- // we can draw circles in any style
- bool isCircle = SkScalarNearlyEqual(oval.width(), oval.height())
- && circleStaysCircle(this->getMatrix());
- // and for now, axis-aligned ellipses only with fill or stroke-and-fill
- SkStrokeRec::Style style = stroke.getStyle();
- bool isStroke = (style == SkStrokeRec::kStroke_Style || style == SkStrokeRec::kHairline_Style);
- bool isFilledAxisAlignedEllipse = this->getMatrix().rectStaysRect() && !isStroke;
+ // we can draw circles
+ *isCircle = SkScalarNearlyEqual(oval.width(), oval.height())
+ && circleStaysCircle(this->getMatrix());
+ // and axis-aligned ellipses only
+ bool isAxisAlignedEllipse = this->getMatrix().rectStaysRect();
- return isCircle || isFilledAxisAlignedEllipse;
+ return *isCircle || isAxisAlignedEllipse;
}
void GrContext::internalDrawOval(const GrPaint& paint,
const GrRect& oval,
const SkStrokeRec& stroke) {
-
- SkScalar xRadius = SkScalarHalf(oval.width());
- SkScalar yRadius = SkScalarHalf(oval.height());
-
- SkScalar strokeWidth = stroke.getWidth();
- SkStrokeRec::Style style = stroke.getStyle();
-
- bool isCircle = SkScalarNearlyEqual(xRadius, yRadius) && circleStaysCircle(this->getMatrix());
#ifdef SK_DEBUG
{
// we should have checked for this previously
- bool isStroke = (style == SkStrokeRec::kStroke_Style || style == SkStrokeRec::kHairline_Style);
- bool isFilledAxisAlignedEllipse = this->getMatrix().rectStaysRect() && !isStroke;
- SkASSERT(paint.isAntiAlias() && (isCircle || isFilledAxisAlignedEllipse));
+ bool isAxisAlignedEllipse = this->getMatrix().rectStaysRect();
+ SkASSERT(paint.isAntiAlias() && isAxisAlignedEllipse);
}
#endif
-
GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW);
GrDrawState* drawState = target->drawState();
GrDrawState::AutoStageDisable atr(fDrawState);
- const SkMatrix vm = drawState->getViewMatrix();
const GrRenderTarget* rt = drawState->getRenderTarget();
if (NULL == rt) {
return;
}
+ const SkMatrix vm = drawState->getViewMatrix();
+
GrDrawState::AutoDeviceCoordDraw adcd(drawState);
if (!adcd.succeeded()) {
return;
@@ -1075,11 +1083,12 @@ void GrContext::internalDrawOval(const GrPaint& paint,
// position + edge
static const GrVertexAttrib kVertexAttribs[] = {
{kVec2f_GrVertexAttribType, 0},
- {kVec4f_GrVertexAttribType, sizeof(GrPoint)}
+ {kVec2f_GrVertexAttribType, sizeof(GrPoint)},
+ {kVec4f_GrVertexAttribType, 2*sizeof(GrPoint)}
};
drawState->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs));
drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0);
- GrAssert(sizeof(CircleVertex) == drawState->getVertexSize());
+ GrAssert(sizeof(EllipseVertex) == drawState->getVertexSize());
GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
if (!geo.succeeded()) {
@@ -1087,97 +1096,182 @@ void GrContext::internalDrawOval(const GrPaint& paint,
return;
}
- CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices());
+ EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices());
GrPoint center = GrPoint::Make(oval.centerX(), oval.centerY());
vm.mapPoints(&center, 1);
- SkScalar L;
- SkScalar R;
- SkScalar T;
- SkScalar B;
+ SkStrokeRec::Style style = stroke.getStyle();
+ bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style);
+ enum {
+ // the edge effects share this stage with glyph rendering
+ // (kGlyphMaskStage in GrTextContext) && SW path rendering
+ // (kPathMaskStage in GrSWMaskHelper)
+ kEdgeEffectStage = GrPaint::kTotalStages,
+ };
+ drawState->setAttribBindings(GrDrawState::kDefault_AttribBindings);
- if (isCircle) {
- drawState->setAttribBindings(GrDrawState::kEdge_AttribBindingsBit);
- drawState->setVertexEdgeType(GrDrawState::kCircle_EdgeType);
- drawState->setAttribIndex(GrDrawState::kEdge_AttribIndex, 1);
-
- xRadius = vm.mapRadius(xRadius);
-
- SkScalar outerRadius = xRadius;
- SkScalar innerRadius = 0;
- SkScalar halfWidth = 0;
- if (style != SkStrokeRec::kFill_Style) {
- strokeWidth = vm.mapRadius(strokeWidth);
- if (SkScalarNearlyZero(strokeWidth)) {
- halfWidth = SK_ScalarHalf;
- } else {
- halfWidth = SkScalarHalf(strokeWidth);
- }
+ GrEffectRef* effect = GrEllipseEdgeEffect::Create(isStroked);
+ static const int kEllipseCenterAttrIndex = 1;
+ static const int kEllipseEdgeAttrIndex = 2;
+ drawState->setEffect(kEdgeEffectStage, effect,
+ kEllipseCenterAttrIndex, kEllipseEdgeAttrIndex)->unref();
- outerRadius += halfWidth;
- if (style == SkStrokeRec::kStroke_Style || style == SkStrokeRec::kHairline_Style) {
- innerRadius = SkMaxScalar(0, xRadius - halfWidth);
- }
- }
+ SkRect xformedRect;
+ vm.mapRect(&xformedRect, oval);
+
+ SkScalar xRadius = SkScalarHalf(xformedRect.width());
+ SkScalar yRadius = SkScalarHalf(xformedRect.height());
+ SkScalar innerXRadius = 0.0f;
+ SkScalar innerRatio = 1.0f;
+
+ if (SkStrokeRec::kFill_Style != style) {
+ SkScalar strokeWidth = stroke.getWidth();
- for (int i = 0; i < 4; ++i) {
- verts[i].fCenter = center;
- verts[i].fOuterRadius = outerRadius;
- verts[i].fInnerRadius = innerRadius;
+ // do (potentially) anisotropic mapping
+ SkVector scaledStroke;
+ scaledStroke.set(strokeWidth, strokeWidth);
+ vm.mapVectors(&scaledStroke, 1);
+
+ if (SkScalarNearlyZero(scaledStroke.length())) {
+ scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
+ } else {
+ scaledStroke.scale(0.5f);
}
- L = -outerRadius;
- R = +outerRadius;
- T = -outerRadius;
- B = +outerRadius;
- } else { // is axis-aligned ellipse
- drawState->setAttribBindings(GrDrawState::kDefault_AttribBindings);
-
- enum {
- // the edge effects share this stage with glyph rendering
- // (kGlyphMaskStage in GrTextContext) && SW path rendering
- // (kPathMaskStage in GrSWMaskHelper)
- kEdgeEffectStage = GrPaint::kTotalStages,
- };
- GrEffectRef* effect = GrEllipseEdgeEffect::Create();
- static const int kEdgeAttrIndex = 1;
- drawState->setEffect(kEdgeEffectStage, effect, &kEdgeAttrIndex)->unref();
-
- SkRect xformedRect;
- vm.mapRect(&xformedRect, oval);
-
- xRadius = SkScalarHalf(xformedRect.width());
- yRadius = SkScalarHalf(xformedRect.height());
-
- if (style == SkStrokeRec::kStrokeAndFill_Style && strokeWidth > 0.0f) {
- SkScalar halfWidth = SkScalarHalf(strokeWidth);
- // do (potentially) anisotropic mapping
- SkVector scaledStroke;
- scaledStroke.set(halfWidth, halfWidth);
- vm.mapVectors(&scaledStroke, 1);
- // this is legit only if scale & translation (which should be the case at the moment)
- xRadius += scaledStroke.fX;
- yRadius += scaledStroke.fY;
+ // this is legit only if scale & translation (which should be the case at the moment)
+ if (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style) {
+ SkScalar innerYRadius = SkMaxScalar(0, yRadius - scaledStroke.fY);
+ if (innerYRadius > SK_ScalarNearlyZero) {
+ innerXRadius = SkMaxScalar(0, xRadius - scaledStroke.fX);
+ innerRatio = innerXRadius/innerYRadius;
+ }
}
+ xRadius += scaledStroke.fX;
+ yRadius += scaledStroke.fY;
+ }
+
+ SkScalar outerRatio = SkScalarDiv(xRadius, yRadius);
+
+ for (int i = 0; i < 4; ++i) {
+ verts[i].fCenter = center;
+ verts[i].fOuterXRadius = xRadius + 0.5f;
+ verts[i].fOuterXYRatio = outerRatio;
+ verts[i].fInnerXRadius = innerXRadius - 0.5f;
+ verts[i].fInnerXYRatio = innerRatio;
+ }
+
+ SkScalar L = -xRadius;
+ SkScalar R = +xRadius;
+ SkScalar T = -yRadius;
+ SkScalar B = +yRadius;
+
+ // We've extended the outer x radius out half a pixel to antialias.
+ // Expand the drawn rect here so all the pixels will be captured.
+ L += center.fX - SK_ScalarHalf;
+ R += center.fX + SK_ScalarHalf;
+ T += center.fY - SK_ScalarHalf;
+ B += center.fY + SK_ScalarHalf;
+
+ verts[0].fPos = SkPoint::Make(L, T);
+ verts[1].fPos = SkPoint::Make(R, T);
+ verts[2].fPos = SkPoint::Make(L, B);
+ verts[3].fPos = SkPoint::Make(R, B);
+
+ target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4);
+}
+
+void GrContext::internalDrawCircle(const GrPaint& paint,
+ const GrRect& circle,
+ const SkStrokeRec& stroke) {
+
+ SkScalar radius = SkScalarHalf(circle.width());
+
+ SkScalar strokeWidth = stroke.getWidth();
+ SkStrokeRec::Style style = stroke.getStyle();
+
+ GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW);
+
+ GrDrawState* drawState = target->drawState();
+ GrDrawState::AutoStageDisable atr(fDrawState);
+
+ const GrRenderTarget* rt = drawState->getRenderTarget();
+ if (NULL == rt) {
+ return;
+ }
+
+ const SkMatrix vm = drawState->getViewMatrix();
+
+ GrDrawState::AutoDeviceCoordDraw adcd(drawState);
+ if (!adcd.succeeded()) {
+ return;
+ }
+
+ // position + edge
+ static const GrVertexAttrib kVertexAttribs[] = {
+ {kVec2f_GrVertexAttribType, 0},
+ {kVec4f_GrVertexAttribType, sizeof(GrPoint)}
+ };
+ drawState->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs));
+ drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0);
+ GrAssert(sizeof(CircleVertex) == drawState->getVertexSize());
- SkScalar ratio = SkScalarDiv(xRadius, yRadius);
+ GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
+ if (!geo.succeeded()) {
+ GrPrintf("Failed to get space for vertices!\n");
+ return;
+ }
- for (int i = 0; i < 4; ++i) {
- verts[i].fCenter = center;
- verts[i].fOuterRadius = xRadius;
- verts[i].fInnerRadius = ratio;
+ CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices());
+
+ GrPoint center = GrPoint::Make(circle.centerX(), circle.centerY());
+ vm.mapPoints(&center, 1);
+
+ bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style);
+ enum {
+ // the edge effects share this stage with glyph rendering
+ // (kGlyphMaskStage in GrTextContext) && SW path rendering
+ // (kPathMaskStage in GrSWMaskHelper)
+ kEdgeEffectStage = GrPaint::kTotalStages,
+ };
+ drawState->setAttribBindings(GrDrawState::kDefault_AttribBindings);
+
+ GrEffectRef* effect = GrCircleEdgeEffect::Create(isStroked);
+ static const int kCircleEdgeAttrIndex = 1;
+ drawState->setEffect(kEdgeEffectStage, effect, kCircleEdgeAttrIndex)->unref();
+
+ radius = vm.mapRadius(radius);
+
+ SkScalar innerRadius = -2.0f;
+ SkScalar outerRadius = radius;
+ SkScalar halfWidth = 0;
+ if (style != SkStrokeRec::kFill_Style) {
+ strokeWidth = vm.mapRadius(strokeWidth);
+ if (SkScalarNearlyZero(strokeWidth)) {
+ halfWidth = SK_ScalarHalf;
+ } else {
+ halfWidth = SkScalarHalf(strokeWidth);
+ }
+
+ outerRadius += halfWidth;
+ if (isStroked) {
+ innerRadius = SkMaxScalar(0, radius - halfWidth);
}
+ }
- L = -xRadius;
- R = +xRadius;
- T = -yRadius;
- B = +yRadius;
+ for (int i = 0; i < 4; ++i) {
+ verts[i].fCenter = center;
+ verts[i].fOuterRadius = outerRadius + 0.5f;
+ verts[i].fInnerRadius = innerRadius - 0.5f;
}
- // The fragment shader will extend the radius out half a pixel
- // to antialias. Expand the drawn rect here so all the pixels
- // will be captured.
+ SkScalar L = -outerRadius;
+ SkScalar R = +outerRadius;
+ SkScalar T = -outerRadius;
+ SkScalar B = +outerRadius;
+
+ // We've extended the outer radius out half a pixel to antialias.
+ // Expand the drawn rect here so all the pixels will be captured.
L += center.fX - SK_ScalarHalf;
R += center.fX + SK_ScalarHalf;
T += center.fY - SK_ScalarHalf;
@@ -1203,15 +1297,21 @@ void GrContext::drawPath(const GrPaint& paint, const SkPath& path, const SkStrok
SkRect ovalRect;
bool isOval = path.isOval(&ovalRect);
- if (isOval && !path.isInverseFillType() && this->canDrawOval(paint, ovalRect, stroke)) {
- this->drawOval(paint, ovalRect, stroke);
+ bool isCircle;
+ if (isOval && !path.isInverseFillType() && this->canDrawOval(paint, ovalRect, &isCircle)) {
+ if (isCircle) {
+ this->internalDrawCircle(paint, ovalRect, stroke);
+ } else {
+ this->internalDrawOval(paint, ovalRect, stroke);
+ }
return;
}
this->internalDrawPath(paint, path, stroke);
}
-void GrContext::internalDrawPath(const GrPaint& paint, const SkPath& path, const SkStrokeRec& stroke) {
+void GrContext::internalDrawPath(const GrPaint& paint, const SkPath& path,
+ const SkStrokeRec& stroke) {
// Note that below we may sw-rasterize the path into a scratch texture.
// Scratch textures can be recycled after they are returned to the texture
diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h
index 4e9747d755..6ee6df5ed2 100644
--- a/src/gpu/GrDrawState.h
+++ b/src/gpu/GrDrawState.h
@@ -485,9 +485,14 @@ public:
/// @name Effect Stages
////
+ const GrEffectRef* setEffect(int stageIdx, const GrEffectRef* effect) {
+ fStages[stageIdx].setEffect(effect);
+ return effect;
+ }
+
const GrEffectRef* setEffect(int stageIdx, const GrEffectRef* effect,
- const int* indices = NULL) {
- fStages[stageIdx].setEffect(effect, indices);
+ int attr0, int attr1 = -1) {
+ fStages[stageIdx].setEffect(effect, attr0, attr1);
return effect;
}
@@ -518,7 +523,7 @@ public:
}
void disableStage(int stageIdx) {
- this->setEffect(stageIdx, NULL, NULL);
+ this->setEffect(stageIdx, NULL);
}
/**
@@ -1023,9 +1028,6 @@ public:
/* Same as above but for hairline quadratics. Uses unsigned distance.
Coverage is min(0, 1-distance). */
kHairQuad_EdgeType,
- /* Circle specified as center_x, center_y, outer_radius, inner_radius
- all in window space (y-down). */
- kCircle_EdgeType,
kVertexEdgeTypeCnt
};
diff --git a/src/gpu/effects/GrCircleEdgeEffect.cpp b/src/gpu/effects/GrCircleEdgeEffect.cpp
new file mode 100644
index 0000000000..e430464442
--- /dev/null
+++ b/src/gpu/effects/GrCircleEdgeEffect.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrCircleEdgeEffect.h"
+#include "gl/GrGLEffect.h"
+#include "gl/GrGLEffectMatrix.h"
+#include "gl/GrGLSL.h"
+#include "gl/GrGLTexture.h"
+#include "GrTBackendEffectFactory.h"
+#include "GrTexture.h"
+
+#include "SkRTConf.h"
+
+class GrGLCircleEdgeEffect : public GrGLEffect {
+public:
+ GrGLCircleEdgeEffect(const GrBackendEffectFactory& factory, const GrEffectRef&)
+ : INHERITED (factory) {}
+
+ virtual void emitCode(GrGLShaderBuilder* builder,
+ const GrEffectStage& stage,
+ EffectKey key,
+ const char* vertexCoords,
+ const char* outputColor,
+ const char* inputColor,
+ const TextureSamplerArray& samplers) SK_OVERRIDE {
+ const GrCircleEdgeEffect& effect = GetEffectFromStage<GrCircleEdgeEffect>(stage);
+
+ const char *vsName, *fsName;
+ builder->addVarying(kVec4f_GrSLType, "CircleEdge", &vsName, &fsName);
+
+ const SkString* attrName =
+ builder->getEffectAttributeName(stage.getVertexAttribIndices()[0]);
+ builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str());
+
+ builder->fsCodeAppendf("\tfloat d = distance(%s.xy, %s.xy);\n",
+ builder->fragmentPosition(), fsName);
+ builder->fsCodeAppendf("\tfloat edgeAlpha = clamp(%s.z - d, 0.0, 1.0);\n", fsName);
+ if (effect.isStroked()) {
+ builder->fsCodeAppendf("\tfloat innerAlpha = clamp(d - %s.w, 0.0, 1.0);\n", fsName);
+ builder->fsCodeAppend("\tedgeAlpha *= innerAlpha;\n");
+ }
+ SkString modulate;
+ GrGLSLModulate4f(&modulate, inputColor, "edgeAlpha");
+ builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
+ }
+
+ static inline EffectKey GenKey(const GrEffectStage& stage, const GrGLCaps&) {
+ const GrCircleEdgeEffect& effect = GetEffectFromStage<GrCircleEdgeEffect>(stage);
+
+ return effect.isStroked() ? 0x1 : 0x0;
+ }
+
+ virtual void setData(const GrGLUniformManager& uman, const GrEffectStage& stage) SK_OVERRIDE {
+ }
+
+private:
+ typedef GrGLEffect INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrCircleEdgeEffect::GrCircleEdgeEffect(bool stroke) : GrEffect() {
+ this->addVertexAttrib(kVec4f_GrSLType);
+ fStroke = stroke;
+}
+
+void GrCircleEdgeEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
+ *validFlags = 0;
+}
+
+const GrBackendEffectFactory& GrCircleEdgeEffect::getFactory() const {
+ return GrTBackendEffectFactory<GrCircleEdgeEffect>::getInstance();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+GR_DEFINE_EFFECT_TEST(GrCircleEdgeEffect);
+
+GrEffectRef* GrCircleEdgeEffect::TestCreate(SkMWCRandom* random,
+ GrContext* context,
+ GrTexture* textures[]) {
+ return GrCircleEdgeEffect::Create(random->nextBool());
+}
diff --git a/src/gpu/effects/GrCircleEdgeEffect.h b/src/gpu/effects/GrCircleEdgeEffect.h
new file mode 100644
index 0000000000..6bd892e135
--- /dev/null
+++ b/src/gpu/effects/GrCircleEdgeEffect.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrCircleEdgeEffect_DEFINED
+#define GrCircleEdgeEffect_DEFINED
+
+#include "GrEffect.h"
+
+class GrGLCircleEdgeEffect;
+
+/**
+ * The output of this effect is a modulation of the input color and coverage for a circle,
+ * specified as center_x, center_y, x_radius, inner radius and outer radius in window space
+ * (y-down).
+ */
+
+class GrCircleEdgeEffect : public GrEffect {
+public:
+ static GrEffectRef* Create(bool stroke) {
+ // we go through this so we only have one copy of each effect (stroked/filled)
+ static SkAutoTUnref<GrEffectRef> gCircleStrokeEdgeEffectRef(
+ CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(GrCircleEdgeEffect, (true)))));
+ static SkAutoTUnref<GrEffectRef> gCircleFillEdgeEffectRef(
+ CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(GrCircleEdgeEffect, (false)))));
+
+ if (stroke) {
+ gCircleStrokeEdgeEffectRef.get()->ref();
+ return gCircleStrokeEdgeEffectRef;
+ } else {
+ gCircleFillEdgeEffectRef.get()->ref();
+ return gCircleFillEdgeEffectRef;
+ }
+ }
+
+ virtual ~GrCircleEdgeEffect() {}
+
+ static const char* Name() { return "CircleEdge"; }
+
+ virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
+
+ typedef GrGLCircleEdgeEffect GLEffect;
+
+ virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
+
+ inline bool isStroked() const { return fStroke; }
+
+private:
+ GrCircleEdgeEffect(bool stroke);
+
+ virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
+ return true;
+ }
+
+ bool fStroke;
+
+ GR_DECLARE_EFFECT_TEST;
+
+ typedef GrEffect INHERITED;
+};
+
+#endif
diff --git a/src/gpu/effects/GrEllipseEdgeEffect.cpp b/src/gpu/effects/GrEllipseEdgeEffect.cpp
index 18301e9999..f4965f7bf8 100644
--- a/src/gpu/effects/GrEllipseEdgeEffect.cpp
+++ b/src/gpu/effects/GrEllipseEdgeEffect.cpp
@@ -25,27 +25,49 @@ public:
const char* outputColor,
const char* inputColor,
const TextureSamplerArray& samplers) SK_OVERRIDE {
- const char *vsName, *fsName;
- builder->addVarying(kVec4f_GrSLType, "EllipseEdge", &vsName, &fsName);
+ const GrEllipseEdgeEffect& effect = GetEffectFromStage<GrEllipseEdgeEffect>(stage);
+
+ const char *vsCenterName, *fsCenterName;
+ const char *vsEdgeName, *fsEdgeName;
- const SkString* attrName = builder->getEffectAttributeName(stage.getVertexAttribIndices()[0]);
- builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str());
+ builder->addVarying(kVec2f_GrSLType, "EllipseCenter", &vsCenterName, &fsCenterName);
+ const SkString* attr0Name =
+ builder->getEffectAttributeName(stage.getVertexAttribIndices()[0]);
+ builder->vsCodeAppendf("\t%s = %s;\n", vsCenterName, attr0Name->c_str());
+
+ builder->addVarying(kVec4f_GrSLType, "EllipseEdge", &vsEdgeName, &fsEdgeName);
+ const SkString* attr1Name =
+ builder->getEffectAttributeName(stage.getVertexAttribIndices()[1]);
+ builder->vsCodeAppendf("\t%s = %s;\n", vsEdgeName, attr1Name->c_str());
- builder->fsCodeAppend("\tfloat edgeAlpha;\n");
// translate to origin
- builder->fsCodeAppendf("\tvec2 offset = (%s.xy - %s.xy);\n", builder->fragmentPosition(), fsName);
+ builder->fsCodeAppendf("\tvec2 outerOffset = (%s.xy - %s.xy);\n",
+ builder->fragmentPosition(), fsCenterName);
+ builder->fsCodeAppend("\tvec2 innerOffset = outerOffset;\n");
// scale y by xRadius/yRadius
- builder->fsCodeAppendf("\toffset.y *= %s.w;\n", fsName);
- builder->fsCodeAppend("\tfloat d = length(offset);\n");
- // compare length against xRadius
- builder->fsCodeAppendf("\tedgeAlpha = smoothstep(d - 0.5, d + 0.5, %s.z);\n", fsName);
+ builder->fsCodeAppendf("\touterOffset.y *= %s.y;\n", fsEdgeName);
+ builder->fsCodeAppend("\tfloat dOuter = length(outerOffset);\n");
+ // compare outer lengths against xOuterRadius
+ builder->fsCodeAppendf("\tfloat edgeAlpha = clamp(%s.x-dOuter, 0.0, 1.0);\n", fsEdgeName);
+
+ if (effect.isStroked()) {
+ builder->fsCodeAppendf("\tinnerOffset.y *= %s.w;\n", fsEdgeName);
+ builder->fsCodeAppend("\tfloat dInner = length(innerOffset);\n");
+
+ // compare inner lengths against xInnerRadius
+ builder->fsCodeAppendf("\tfloat innerAlpha = clamp(dInner-%s.z, 0.0, 1.0);\n", fsEdgeName);
+ builder->fsCodeAppend("\tedgeAlpha *= innerAlpha;\n");
+ }
+
SkString modulate;
GrGLSLModulate4f(&modulate, inputColor, "edgeAlpha");
builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
}
static inline EffectKey GenKey(const GrEffectStage& stage, const GrGLCaps&) {
- return 0;
+ const GrEllipseEdgeEffect& effect = GetEffectFromStage<GrEllipseEdgeEffect>(stage);
+
+ return effect.isStroked() ? 0x1 : 0x0;
}
virtual void setData(const GrGLUniformManager& uman, const GrEffectStage& stage) SK_OVERRIDE {
@@ -57,8 +79,11 @@ private:
///////////////////////////////////////////////////////////////////////////////
-GrEllipseEdgeEffect::GrEllipseEdgeEffect() : GrEffect() {
+GrEllipseEdgeEffect::GrEllipseEdgeEffect(bool stroke) : GrEffect() {
+ this->addVertexAttrib(kVec2f_GrSLType);
this->addVertexAttrib(kVec4f_GrSLType);
+
+ fStroke = stroke;
}
void GrEllipseEdgeEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
@@ -76,5 +101,5 @@ GR_DEFINE_EFFECT_TEST(GrEllipseEdgeEffect);
GrEffectRef* GrEllipseEdgeEffect::TestCreate(SkMWCRandom* random,
GrContext* context,
GrTexture* textures[]) {
- return GrEllipseEdgeEffect::Create();
+ return GrEllipseEdgeEffect::Create(random->nextBool());
}
diff --git a/src/gpu/effects/GrEllipseEdgeEffect.h b/src/gpu/effects/GrEllipseEdgeEffect.h
index 31c6b09a0f..5eada2c96c 100644
--- a/src/gpu/effects/GrEllipseEdgeEffect.h
+++ b/src/gpu/effects/GrEllipseEdgeEffect.h
@@ -19,10 +19,20 @@ class GrGLEllipseEdgeEffect;
class GrEllipseEdgeEffect : public GrEffect {
public:
- static GrEffectRef* Create() {
- // maybe only have one static copy?
- AutoEffectUnref effect(SkNEW(GrEllipseEdgeEffect));
- return CreateEffectRef(effect);
+ static GrEffectRef* Create(bool stroke) {
+ // we go through this so we only have one copy of each effect (stroked/filled)
+ static SkAutoTUnref<GrEffectRef> gEllipseStrokeEdgeEffectRef(
+ CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(GrEllipseEdgeEffect, (true)))));
+ static SkAutoTUnref<GrEffectRef> gEllipseFillEdgeEffectRef(
+ CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(GrEllipseEdgeEffect, (false)))));
+
+ if (stroke) {
+ gEllipseStrokeEdgeEffectRef.get()->ref();
+ return gEllipseStrokeEdgeEffectRef;
+ } else {
+ gEllipseFillEdgeEffectRef.get()->ref();
+ return gEllipseFillEdgeEffectRef;
+ }
}
virtual ~GrEllipseEdgeEffect() {}
@@ -35,13 +45,17 @@ public:
virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
+ inline bool isStroked() const { return fStroke; }
+
private:
- GrEllipseEdgeEffect();
+ GrEllipseEdgeEffect(bool stroke);
virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE {
return true;
}
+ bool fStroke;
+
GR_DECLARE_EFFECT_TEST;
typedef GrEffect INHERITED;
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index 850f0bb134..7d6420ead4 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -23,7 +23,8 @@ SK_DEFINE_INST_COUNT(GrGLProgram)
#define GL_CALL(X) GR_GL_CALL(fContext.interface(), X)
#define GL_CALL_RET(R, X) GR_GL_CALL_RET(fContext.interface(), R, X)
-SK_CONF_DECLARE(bool, c_PrintShaders, "gpu.printShaders", false, "Print the source code for all shaders generated.");
+SK_CONF_DECLARE(bool, c_PrintShaders, "gpu.printShaders", false,
+ "Print the source code for all shaders generated.");
#define TEX_ATTR_NAME "aTexCoord"
#define COL_ATTR_NAME "aColor"
@@ -69,15 +70,16 @@ void GrGLProgram::BuildDesc(const GrDrawState& drawState,
desc->fEmitsPointSize = isPoints;
- bool requiresAttributeColors = !skipColor &&
- SkToBool(desc->fAttribBindings & GrDrawState::kColor_AttribBindingsBit);
- bool requiresAttributeCoverage = !skipCoverage &&
- SkToBool(desc->fAttribBindings & GrDrawState::kCoverage_AttribBindingsBit);
+ bool requiresAttributeColors =
+ !skipColor && SkToBool(desc->fAttribBindings & GrDrawState::kColor_AttribBindingsBit);
+ bool requiresAttributeCoverage =
+ !skipCoverage && SkToBool(desc->fAttribBindings & GrDrawState::kCoverage_AttribBindingsBit);
// fColorInput/fCoverageInput records how colors are specified for the program So we strip the
// bits from the bindings to avoid false negatives when searching for an existing program in the
// cache.
- desc->fAttribBindings &= ~(GrDrawState::kColor_AttribBindingsBit | GrDrawState::kCoverage_AttribBindingsBit);
+ desc->fAttribBindings &=
+ ~(GrDrawState::kColor_AttribBindingsBit | GrDrawState::kCoverage_AttribBindingsBit);
desc->fColorFilterXfermode = skipColor ?
SkXfermode::kDst_Mode :
@@ -423,7 +425,8 @@ bool GrGLProgram::genEdgeCoverage(SkString* coverageVar,
builder->vsCodeAppendf("\t%s = " EDGE_ATTR_NAME ";\n", vsName);
switch (fDesc.fVertexEdgeType) {
case GrDrawState::kHairLine_EdgeType:
- builder->fsCodeAppendf("\tfloat edgeAlpha = abs(dot(vec3(%s.xy,1), %s.xyz));\n", builder->fragmentPosition(), fsName);
+ builder->fsCodeAppendf("\tfloat edgeAlpha = abs(dot(vec3(%s.xy,1), %s.xyz));\n",
+ builder->fragmentPosition(), fsName);
builder->fsCodeAppendf("\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
break;
case GrDrawState::kQuad_EdgeType:
@@ -433,7 +436,8 @@ bool GrGLProgram::genEdgeCoverage(SkString* coverageVar,
builder->fsCodeAppendf("\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
builder->fsCodeAppendf("\tif (%s.z > 0.0 && %s.w > 0.0) {\n", fsName, fsName);
// today we know z and w are in device space. We could use derivatives
- builder->fsCodeAppendf("\t\tedgeAlpha = min(min(%s.z, %s.w) + 0.5, 1.0);\n", fsName, fsName);
+ builder->fsCodeAppendf("\t\tedgeAlpha = min(min(%s.z, %s.w) + 0.5, 1.0);\n", fsName,
+ fsName);
builder->fsCodeAppendf ("\t} else {\n");
builder->fsCodeAppendf("\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
"\t\t 2.0*%s.x*duvdy.x - duvdy.y);\n",
@@ -451,20 +455,14 @@ bool GrGLProgram::genEdgeCoverage(SkString* coverageVar,
builder->fsCodeAppendf("\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
"\t 2.0*%s.x*duvdy.x - duvdy.y);\n",
fsName, fsName);
- builder->fsCodeAppendf("\tfloat edgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName, fsName);
+ builder->fsCodeAppendf("\tfloat edgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName,
+ fsName);
builder->fsCodeAppend("\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / dot(gF, gF));\n");
builder->fsCodeAppend("\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
if (kES2_GrGLBinding == fContext.info().binding()) {
builder->fHeader.printf("#extension GL_OES_standard_derivatives: enable\n");
}
break;
- case GrDrawState::kCircle_EdgeType:
- builder->fsCodeAppend("\tfloat edgeAlpha;\n");
- builder->fsCodeAppendf("\tfloat d = distance(%s.xy, %s.xy);\n", builder->fragmentPosition(), fsName);
- builder->fsCodeAppendf("\tfloat outerAlpha = smoothstep(d - 0.5, d + 0.5, %s.z);\n", fsName);
- builder->fsCodeAppendf("\tfloat innerAlpha = %s.w == 0.0 ? 1.0 : smoothstep(%s.w - 0.5, %s.w + 0.5, d);\n", fsName, fsName, fsName);
- builder->fsCodeAppend("\tedgeAlpha = outerAlpha * innerAlpha;\n");
- break;
default:
GrCrash("Unknown Edge Type!");
break;
@@ -905,7 +903,9 @@ bool GrGLProgram::genProgram(const GrEffectStage* stages[]) {
// discard if coverage is zero
if (fDesc.fDiscardIfOutsideEdge && !outCoverage.isEmpty()) {
- builder.fsCodeAppendf("\tif (all(lessThanEqual(%s, vec4(0.0)))) {\n\t\tdiscard;\n\t}\n", outCoverage.c_str());
+ builder.fsCodeAppendf(
+ "\tif (all(lessThanEqual(%s, vec4(0.0)))) {\n\t\tdiscard;\n\t}\n",
+ outCoverage.c_str());
}
}
diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp
index b56c788513..d12aeb57dd 100644
--- a/tests/GLProgramsTest.cpp
+++ b/tests/GLProgramsTest.cpp
@@ -134,7 +134,7 @@ bool GrGpuGL::programUnitTest(int maxStages) {
for (int i = 0; i < effect.get()->get()->numVertexAttribs(); ++i) {
attribIndices[i] = currAttribIndex++;
}
- stages[s].setEffect(effect.get(), attribIndices);
+ stages[s].setEffect(effect.get(), attribIndices[0], attribIndices[1]);
}
}
pdesc.setRandom(&random, this, stages);