aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/GrOvalRenderer.cpp
diff options
context:
space:
mode:
authorGravatar commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-04-11 15:05:37 +0000
committerGravatar commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-04-11 15:05:37 +0000
commit0a6cb602e5866f7a8cd1630d0c907749f5182837 (patch)
tree5addf9511e0f106a49b69acca74e1e0e36ff0cd7 /src/gpu/GrOvalRenderer.cpp
parent3e475dc8d0a156521bd9963edb80b10398a14160 (diff)
Shader optimization for ovals.
Previously we were setting a center point as an attribute across all vertices, then using that with the interpolated position to compute an offset. However, because the offset computation is linear, we can just set the appropriate offset at the vertices and let the rasterizer interpolate it for us. Author: jvanverth@google.com Reviewed By: robertphillips@google.com Review URL: https://chromiumcodereview.appspot.com/14093002 git-svn-id: http://skia.googlecode.com/svn/trunk@8613 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/gpu/GrOvalRenderer.cpp')
-rw-r--r--src/gpu/GrOvalRenderer.cpp137
1 files changed, 77 insertions, 60 deletions
diff --git a/src/gpu/GrOvalRenderer.cpp b/src/gpu/GrOvalRenderer.cpp
index 61f27f4b90..731964c2d7 100644
--- a/src/gpu/GrOvalRenderer.cpp
+++ b/src/gpu/GrOvalRenderer.cpp
@@ -21,19 +21,18 @@ SK_DEFINE_INST_COUNT(GrOvalRenderer)
namespace {
struct CircleVertex {
- GrPoint fPos;
- GrPoint fCenter;
+ GrPoint fPos;
+ GrPoint fOffset;
SkScalar fOuterRadius;
SkScalar fInnerRadius;
};
struct EllipseVertex {
- GrPoint fPos;
- GrPoint fCenter;
+ GrPoint fPos;
SkScalar fOuterXRadius;
- SkScalar fOuterXYRatio;
SkScalar fInnerXRadius;
- SkScalar fInnerXYRatio;
+ GrPoint fOuterOffset;
+ GrPoint fInnerOffset;
};
inline bool circle_stays_circle(const SkMatrix& m) {
@@ -46,8 +45,7 @@ inline bool circle_stays_circle(const SkMatrix& m) {
/**
* 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).
+ * specified as offset_x, offset_y (both from center point), outer radius and inner radius.
*/
class CircleEdgeEffect : public GrEffect {
@@ -102,13 +100,13 @@ public:
builder->getEffectAttributeName(drawEffect.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 d = length(%s.xy);\n", fsName);
builder->fsCodeAppendf("\tfloat edgeAlpha = clamp(%s.z - d, 0.0, 1.0);\n", fsName);
if (circleEffect.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());
@@ -158,7 +156,7 @@ GrEffectRef* CircleEdgeEffect::TestCreate(SkMWCRandom* random,
/**
* The output of this effect is a modulation of the input color and coverage for an axis-aligned
- * ellipse, specified as center_x, center_y, x_radius, x_radius/y_radius in window space (y-down).
+ * ellipse, specified as outer and inner radii, and outer and inner offsets from center.
*/
class EllipseEdgeEffect : public GrEffect {
@@ -207,37 +205,31 @@ public:
const TextureSamplerArray& samplers) SK_OVERRIDE {
const EllipseEdgeEffect& ellipseEffect = drawEffect.castEffect<EllipseEdgeEffect>();
- const char *vsCenterName, *fsCenterName;
- const char *vsEdgeName, *fsEdgeName;
+ const char *vsRadiiName, *fsRadiiName;
+ const char *vsOffsetsName, *fsOffsetsName;
- builder->addVarying(kVec2f_GrSLType, "EllipseCenter", &vsCenterName, &fsCenterName);
+ builder->addVarying(kVec2f_GrSLType, "EllipseRadii", &vsRadiiName, &fsRadiiName);
const SkString* attr0Name =
builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
- builder->vsCodeAppendf("\t%s = %s;\n", vsCenterName, attr0Name->c_str());
+ builder->vsCodeAppendf("\t%s = %s;\n", vsRadiiName, attr0Name->c_str());
- builder->addVarying(kVec4f_GrSLType, "EllipseEdge", &vsEdgeName, &fsEdgeName);
+ builder->addVarying(kVec4f_GrSLType, "EllipseOffsets", &vsOffsetsName, &fsOffsetsName);
const SkString* attr1Name =
builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
- builder->vsCodeAppendf("\t%s = %s;\n", vsEdgeName, attr1Name->c_str());
-
- // translate to origin
- 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("\touterOffset.y *= %s.y;\n", fsEdgeName);
- builder->fsCodeAppend("\tfloat dOuter = length(outerOffset);\n");
+ builder->vsCodeAppendf("\t%s = %s;\n", vsOffsetsName, attr1Name->c_str());
+
+ // get length of offset
+ builder->fsCodeAppendf("\tfloat dOuter = length(%s.xy);\n", fsOffsetsName);
// compare outer lengths against xOuterRadius
builder->fsCodeAppendf("\tfloat edgeAlpha = clamp(%s.x-dOuter, 0.0, 1.0);\n",
- fsEdgeName);
+ fsRadiiName);
if (ellipseEffect.isStroked()) {
- builder->fsCodeAppendf("\tinnerOffset.y *= %s.w;\n", fsEdgeName);
- builder->fsCodeAppend("\tfloat dInner = length(innerOffset);\n");
+ builder->fsCodeAppendf("\tfloat dInner = length(%s.zw);\n", fsOffsetsName);
// compare inner lengths against xInnerRadius
- builder->fsCodeAppendf("\tfloat innerAlpha = clamp(dInner-%s.z, 0.0, 1.0);\n",
- fsEdgeName);
+ builder->fsCodeAppendf("\tfloat innerAlpha = clamp(dInner-%s.y, 0.0, 1.0);\n",
+ fsRadiiName);
builder->fsCodeAppend("\tedgeAlpha *= innerAlpha;\n");
}
@@ -384,12 +376,6 @@ void GrOvalRenderer::drawCircle(GrDrawTarget* target,
outerRadius += SK_ScalarHalf;
innerRadius -= SK_ScalarHalf;
- for (int i = 0; i < 4; ++i) {
- verts[i].fCenter = center;
- verts[i].fOuterRadius = outerRadius;
- verts[i].fInnerRadius = innerRadius;
- }
-
SkRect bounds = SkRect::MakeLTRB(
center.fX - outerRadius,
center.fY - outerRadius,
@@ -398,9 +384,24 @@ void GrOvalRenderer::drawCircle(GrDrawTarget* target,
);
verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop);
+ verts[0].fOffset = SkPoint::Make(-outerRadius, -outerRadius);
+ verts[0].fOuterRadius = outerRadius;
+ verts[0].fInnerRadius = innerRadius;
+
verts[1].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
+ verts[1].fOffset = SkPoint::Make(outerRadius, -outerRadius);
+ verts[1].fOuterRadius = outerRadius;
+ verts[1].fInnerRadius = innerRadius;
+
verts[2].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom);
+ verts[2].fOffset = SkPoint::Make(-outerRadius, outerRadius);
+ verts[2].fOuterRadius = outerRadius;
+ verts[2].fInnerRadius = innerRadius;
+
verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
+ verts[3].fOffset = SkPoint::Make(outerRadius, outerRadius);
+ verts[3].fOuterRadius = outerRadius;
+ verts[3].fInnerRadius = innerRadius;
target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds);
}
@@ -495,30 +496,46 @@ void GrOvalRenderer::drawEllipse(GrDrawTarget* target,
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;
- }
+ // We've extended the outer x radius out half a pixel to antialias.
+ // This will also expand the rect so all the pixels will be captured.
+ xRadius += SK_ScalarHalf;
+ yRadius += SK_ScalarHalf;
+ innerXRadius -= SK_ScalarHalf;
+
+ SkRect bounds = SkRect::MakeLTRB(
+ center.fX - xRadius,
+ center.fY - yRadius,
+ center.fX + xRadius,
+ center.fY + yRadius
+ );
- SkScalar L = -xRadius;
- SkScalar R = +xRadius;
- SkScalar T = -yRadius;
- SkScalar B = +yRadius;
+ // The offsets are created by scaling the y radius by the appropriate ratio. This way we end up
+ // with a circle equation which can be checked quickly in the shader. We need one offset for
+ // outer and one for inner because they have different scale factors -- otherwise we end up with
+ // non-uniform strokes.
+ verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop);
+ verts[0].fOuterXRadius = xRadius;
+ verts[0].fInnerXRadius = innerXRadius;
+ verts[0].fOuterOffset = SkPoint::Make(-xRadius, -outerRatio*yRadius);
+ verts[0].fInnerOffset = SkPoint::Make(-xRadius, -innerRatio*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);
+ verts[1].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
+ verts[1].fOuterXRadius = xRadius;
+ verts[1].fInnerXRadius = innerXRadius;
+ verts[1].fOuterOffset = SkPoint::Make(xRadius, -outerRatio*yRadius);
+ verts[1].fInnerOffset = SkPoint::Make(xRadius, -innerRatio*yRadius);
+
+ verts[2].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom);
+ verts[2].fOuterXRadius = xRadius;
+ verts[2].fInnerXRadius = innerXRadius;
+ verts[2].fOuterOffset = SkPoint::Make(-xRadius, outerRatio*yRadius);
+ verts[2].fInnerOffset = SkPoint::Make(-xRadius, innerRatio*yRadius);
+
+ verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
+ verts[3].fOuterXRadius = xRadius;
+ verts[3].fInnerXRadius = innerXRadius;
+ verts[3].fOuterOffset = SkPoint::Make(xRadius, outerRatio*yRadius);
+ verts[3].fInnerOffset = SkPoint::Make(xRadius, innerRatio*yRadius);
+
+ target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds);
}