Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: src/gpu/GrOvalRenderer.cpp

Issue 14093002: Shader optimization for ovals (Closed) Base URL: http://skia.googlecode.com/svn/trunk/
Patch Set: Add bounds to drawNonIndexed, some cleanup Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2013 Google Inc. 2 * Copyright 2013 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "GrOvalRenderer.h" 8 #include "GrOvalRenderer.h"
9 9
10 #include "GrEffect.h" 10 #include "GrEffect.h"
11 #include "gl/GrGLEffect.h" 11 #include "gl/GrGLEffect.h"
12 #include "gl/GrGLSL.h" 12 #include "gl/GrGLSL.h"
13 #include "GrTBackendEffectFactory.h" 13 #include "GrTBackendEffectFactory.h"
14 14
15 #include "GrDrawState.h" 15 #include "GrDrawState.h"
16 #include "GrDrawTarget.h" 16 #include "GrDrawTarget.h"
17 #include "SkStrokeRec.h" 17 #include "SkStrokeRec.h"
18 18
19 SK_DEFINE_INST_COUNT(GrOvalRenderer) 19 SK_DEFINE_INST_COUNT(GrOvalRenderer)
20 20
21 namespace { 21 namespace {
22 22
23 struct CircleVertex { 23 struct CircleVertex {
24 GrPoint fPos; 24 GrPoint fPos;
25 GrPoint fCenter; 25 GrPoint fOffset;
26 SkScalar fOuterRadius; 26 SkScalar fOuterRadius;
27 SkScalar fInnerRadius; 27 SkScalar fInnerRadius;
28 }; 28 };
29 29
30 struct EllipseVertex { 30 struct EllipseVertex {
31 GrPoint fPos; 31 GrPoint fPos;
32 GrPoint fCenter;
33 SkScalar fOuterXRadius; 32 SkScalar fOuterXRadius;
34 SkScalar fOuterXYRatio;
35 SkScalar fInnerXRadius; 33 SkScalar fInnerXRadius;
36 SkScalar fInnerXYRatio; 34 GrPoint fOuterOffset;
35 GrPoint fInnerOffset;
37 }; 36 };
38 37
39 inline bool circle_stays_circle(const SkMatrix& m) { 38 inline bool circle_stays_circle(const SkMatrix& m) {
40 return m.isSimilarity(); 39 return m.isSimilarity();
41 } 40 }
42 41
43 } 42 }
44 43
45 /////////////////////////////////////////////////////////////////////////////// 44 ///////////////////////////////////////////////////////////////////////////////
46 45
47 /** 46 /**
48 * The output of this effect is a modulation of the input color and coverage for a circle, 47 * The output of this effect is a modulation of the input color and coverage for a circle,
49 * specified as center_x, center_y, x_radius, inner radius and outer radius in w indow space 48 * specified as offset_x, offset_y (both from center point), outer radius and in ner radius.
50 * (y-down).
51 */ 49 */
52 50
53 class CircleEdgeEffect : public GrEffect { 51 class CircleEdgeEffect : public GrEffect {
54 public: 52 public:
55 static GrEffectRef* Create(bool stroke) { 53 static GrEffectRef* Create(bool stroke) {
56 // we go through this so we only have one copy of each effect (stroked/f illed) 54 // we go through this so we only have one copy of each effect (stroked/f illed)
57 static SkAutoTUnref<GrEffectRef> gCircleStrokeEdgeEffectRef( 55 static SkAutoTUnref<GrEffectRef> gCircleStrokeEdgeEffectRef(
58 CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(CircleEdgeEff ect, (true))))); 56 CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(CircleEdgeEff ect, (true)))));
59 static SkAutoTUnref<GrEffectRef> gCircleFillEdgeEffectRef( 57 static SkAutoTUnref<GrEffectRef> gCircleFillEdgeEffectRef(
60 CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(CircleEdgeEff ect, (false))))); 58 CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(CircleEdgeEff ect, (false)))));
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
95 const char* inputColor, 93 const char* inputColor,
96 const TextureSamplerArray& samplers) SK_OVERRIDE { 94 const TextureSamplerArray& samplers) SK_OVERRIDE {
97 const CircleEdgeEffect& circleEffect = drawEffect.castEffect<CircleE dgeEffect>(); 95 const CircleEdgeEffect& circleEffect = drawEffect.castEffect<CircleE dgeEffect>();
98 const char *vsName, *fsName; 96 const char *vsName, *fsName;
99 builder->addVarying(kVec4f_GrSLType, "CircleEdge", &vsName, &fsName) ; 97 builder->addVarying(kVec4f_GrSLType, "CircleEdge", &vsName, &fsName) ;
100 98
101 const SkString* attrName = 99 const SkString* attrName =
102 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[0]); 100 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[0]);
103 builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str()); 101 builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str());
104 102
105 builder->fsCodeAppendf("\tfloat d = distance(%s.xy, %s.xy);\n", 103 builder->fsCodeAppendf("\tfloat d = length(%s.xy);\n", fsName);
106 builder->fragmentPosition(), fsName);
107 builder->fsCodeAppendf("\tfloat edgeAlpha = clamp(%s.z - d, 0.0, 1.0 );\n", fsName); 104 builder->fsCodeAppendf("\tfloat edgeAlpha = clamp(%s.z - d, 0.0, 1.0 );\n", fsName);
108 if (circleEffect.isStroked()) { 105 if (circleEffect.isStroked()) {
109 builder->fsCodeAppendf("\tfloat innerAlpha = clamp(d - %s.w, 0.0 , 1.0);\n", fsName); 106 builder->fsCodeAppendf("\tfloat innerAlpha = clamp(d - %s.w, 0.0 , 1.0);\n", fsName);
110 builder->fsCodeAppend("\tedgeAlpha *= innerAlpha;\n"); 107 builder->fsCodeAppend("\tedgeAlpha *= innerAlpha;\n");
111 } 108 }
109
112 SkString modulate; 110 SkString modulate;
113 GrGLSLModulate4f(&modulate, inputColor, "edgeAlpha"); 111 GrGLSLModulate4f(&modulate, inputColor, "edgeAlpha");
114 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str() ); 112 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str() );
115 } 113 }
116 114
117 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrG LCaps&) { 115 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrG LCaps&) {
118 const CircleEdgeEffect& circleEffect = drawEffect.castEffect<CircleE dgeEffect>(); 116 const CircleEdgeEffect& circleEffect = drawEffect.castEffect<CircleE dgeEffect>();
119 117
120 return circleEffect.isStroked() ? 0x1 : 0x0; 118 return circleEffect.isStroked() ? 0x1 : 0x0;
121 } 119 }
(...skipping 29 matching lines...) Expand all
151 GrContext* context, 149 GrContext* context,
152 const GrDrawTargetCaps&, 150 const GrDrawTargetCaps&,
153 GrTexture* textures[]) { 151 GrTexture* textures[]) {
154 return CircleEdgeEffect::Create(random->nextBool()); 152 return CircleEdgeEffect::Create(random->nextBool());
155 } 153 }
156 154
157 /////////////////////////////////////////////////////////////////////////////// 155 ///////////////////////////////////////////////////////////////////////////////
158 156
159 /** 157 /**
160 * The output of this effect is a modulation of the input color and coverage for an axis-aligned 158 * The output of this effect is a modulation of the input color and coverage for an axis-aligned
161 * ellipse, specified as center_x, center_y, x_radius, x_radius/y_radius in wind ow space (y-down). 159 * ellipse, specified as outer and inner radii, and outer and inner offsets fro m center.
162 */ 160 */
163 161
164 class EllipseEdgeEffect : public GrEffect { 162 class EllipseEdgeEffect : public GrEffect {
165 public: 163 public:
166 static GrEffectRef* Create(bool stroke) { 164 static GrEffectRef* Create(bool stroke) {
167 // we go through this so we only have one copy of each effect (stroked/f illed) 165 // we go through this so we only have one copy of each effect (stroked/f illed)
168 static SkAutoTUnref<GrEffectRef> gEllipseStrokeEdgeEffectRef( 166 static SkAutoTUnref<GrEffectRef> gEllipseStrokeEdgeEffectRef(
169 CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(EllipseEdgeEf fect, (true))))); 167 CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(EllipseEdgeEf fect, (true)))));
170 static SkAutoTUnref<GrEffectRef> gEllipseFillEdgeEffectRef( 168 static SkAutoTUnref<GrEffectRef> gEllipseFillEdgeEffectRef(
171 CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(EllipseEdgeEf fect, (false))))); 169 CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(EllipseEdgeEf fect, (false)))));
(...skipping 28 matching lines...) Expand all
200 : INHERITED (factory) {} 198 : INHERITED (factory) {}
201 199
202 virtual void emitCode(GrGLShaderBuilder* builder, 200 virtual void emitCode(GrGLShaderBuilder* builder,
203 const GrDrawEffect& drawEffect, 201 const GrDrawEffect& drawEffect,
204 EffectKey key, 202 EffectKey key,
205 const char* outputColor, 203 const char* outputColor,
206 const char* inputColor, 204 const char* inputColor,
207 const TextureSamplerArray& samplers) SK_OVERRIDE { 205 const TextureSamplerArray& samplers) SK_OVERRIDE {
208 const EllipseEdgeEffect& ellipseEffect = drawEffect.castEffect<Ellip seEdgeEffect>(); 206 const EllipseEdgeEffect& ellipseEffect = drawEffect.castEffect<Ellip seEdgeEffect>();
209 207
210 const char *vsCenterName, *fsCenterName; 208 const char *vsRadiiName, *fsRadiiName;
211 const char *vsEdgeName, *fsEdgeName; 209 const char *vsOffsetsName, *fsOffsetsName;
212 210
213 builder->addVarying(kVec2f_GrSLType, "EllipseCenter", &vsCenterName, &fsCenterName); 211 builder->addVarying(kVec2f_GrSLType, "EllipseRadii", &vsRadiiName, & fsRadiiName);
214 const SkString* attr0Name = 212 const SkString* attr0Name =
215 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[0]); 213 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[0]);
216 builder->vsCodeAppendf("\t%s = %s;\n", vsCenterName, attr0Name->c_st r()); 214 builder->vsCodeAppendf("\t%s = %s;\n", vsRadiiName, attr0Name->c_str ());
217 215
218 builder->addVarying(kVec4f_GrSLType, "EllipseEdge", &vsEdgeName, &fs EdgeName); 216 builder->addVarying(kVec4f_GrSLType, "EllipseOffsets", &vsOffsetsNam e, &fsOffsetsName);
219 const SkString* attr1Name = 217 const SkString* attr1Name =
220 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[1]); 218 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[1]);
221 builder->vsCodeAppendf("\t%s = %s;\n", vsEdgeName, attr1Name->c_str( )); 219 builder->vsCodeAppendf("\t%s = %s;\n", vsOffsetsName, attr1Name->c_s tr());
222 220
223 // translate to origin 221 // get length of offset
224 builder->fsCodeAppendf("\tvec2 outerOffset = (%s.xy - %s.xy);\n", 222 builder->fsCodeAppendf("\tfloat dOuter = length(%s.xy);\n", fsOffset sName);
225 builder->fragmentPosition(), fsCenterName);
226 builder->fsCodeAppend("\tvec2 innerOffset = outerOffset;\n");
227 // scale y by xRadius/yRadius
228 builder->fsCodeAppendf("\touterOffset.y *= %s.y;\n", fsEdgeName);
229 builder->fsCodeAppend("\tfloat dOuter = length(outerOffset);\n");
230 // compare outer lengths against xOuterRadius 223 // compare outer lengths against xOuterRadius
231 builder->fsCodeAppendf("\tfloat edgeAlpha = clamp(%s.x-dOuter, 0.0, 1.0);\n", 224 builder->fsCodeAppendf("\tfloat edgeAlpha = clamp(%s.x-dOuter, 0.0, 1.0);\n",
232 fsEdgeName); 225 fsRadiiName);
233 226
234 if (ellipseEffect.isStroked()) { 227 if (ellipseEffect.isStroked()) {
235 builder->fsCodeAppendf("\tinnerOffset.y *= %s.w;\n", fsEdgeName) ; 228 builder->fsCodeAppendf("\tfloat dInner = length(%s.zw);\n", fsOf fsetsName);
236 builder->fsCodeAppend("\tfloat dInner = length(innerOffset);\n") ;
237 229
238 // compare inner lengths against xInnerRadius 230 // compare inner lengths against xInnerRadius
239 builder->fsCodeAppendf("\tfloat innerAlpha = clamp(dInner-%s.z, 0.0, 1.0);\n", 231 builder->fsCodeAppendf("\tfloat innerAlpha = clamp(dInner-%s.y, 0.0, 1.0);\n",
240 fsEdgeName); 232 fsRadiiName);
241 builder->fsCodeAppend("\tedgeAlpha *= innerAlpha;\n"); 233 builder->fsCodeAppend("\tedgeAlpha *= innerAlpha;\n");
242 } 234 }
243 235
244 SkString modulate; 236 SkString modulate;
245 GrGLSLModulate4f(&modulate, inputColor, "edgeAlpha"); 237 GrGLSLModulate4f(&modulate, inputColor, "edgeAlpha");
246 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str() ); 238 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str() );
247 } 239 }
248 240
249 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrG LCaps&) { 241 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrG LCaps&) {
250 const EllipseEdgeEffect& ellipseEffect = drawEffect.castEffect<Ellip seEdgeEffect>(); 242 const EllipseEdgeEffect& ellipseEffect = drawEffect.castEffect<Ellip seEdgeEffect>();
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
377 } 369 }
378 } 370 }
379 371
380 // The radii are outset for two reasons. First, it allows the shader to simp ly perform 372 // The radii are outset for two reasons. First, it allows the shader to simp ly perform
381 // clamp(distance-to-center - radius, 0, 1). Second, the outer radius is use d to compute the 373 // clamp(distance-to-center - radius, 0, 1). Second, the outer radius is use d to compute the
382 // verts of the bounding box that is rendered and the outset ensures the box will cover all 374 // verts of the bounding box that is rendered and the outset ensures the box will cover all
383 // pixels partially covered by the circle. 375 // pixels partially covered by the circle.
384 outerRadius += SK_ScalarHalf; 376 outerRadius += SK_ScalarHalf;
385 innerRadius -= SK_ScalarHalf; 377 innerRadius -= SK_ScalarHalf;
386 378
387 for (int i = 0; i < 4; ++i) {
388 verts[i].fCenter = center;
389 verts[i].fOuterRadius = outerRadius;
390 verts[i].fInnerRadius = innerRadius;
391 }
392
393 SkRect bounds = SkRect::MakeLTRB( 379 SkRect bounds = SkRect::MakeLTRB(
394 center.fX - outerRadius, 380 center.fX - outerRadius,
395 center.fY - outerRadius, 381 center.fY - outerRadius,
396 center.fX + outerRadius, 382 center.fX + outerRadius,
397 center.fY + outerRadius 383 center.fY + outerRadius
398 ); 384 );
399 385
400 verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop); 386 verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop);
387 verts[0].fOffset = SkPoint::Make(-outerRadius, -outerRadius);
388 verts[0].fOuterRadius = outerRadius;
389 verts[0].fInnerRadius = innerRadius;
390
401 verts[1].fPos = SkPoint::Make(bounds.fRight, bounds.fTop); 391 verts[1].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
392 verts[1].fOffset = SkPoint::Make(outerRadius, -outerRadius);
393 verts[1].fOuterRadius = outerRadius;
394 verts[1].fInnerRadius = innerRadius;
395
402 verts[2].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom); 396 verts[2].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom);
397 verts[2].fOffset = SkPoint::Make(-outerRadius, outerRadius);
398 verts[2].fOuterRadius = outerRadius;
399 verts[2].fInnerRadius = innerRadius;
400
403 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom); 401 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
402 verts[3].fOffset = SkPoint::Make(outerRadius, outerRadius);
403 verts[3].fOuterRadius = outerRadius;
404 verts[3].fInnerRadius = innerRadius;
404 405
405 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds); 406 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds);
406 } 407 }
407 408
408 void GrOvalRenderer::drawEllipse(GrDrawTarget* target, 409 void GrOvalRenderer::drawEllipse(GrDrawTarget* target,
409 const GrPaint& paint, 410 const GrPaint& paint,
410 const GrRect& ellipse, 411 const GrRect& ellipse,
411 const SkStrokeRec& stroke) 412 const SkStrokeRec& stroke)
412 { 413 {
413 GrDrawState* drawState = target->drawState(); 414 GrDrawState* drawState = target->drawState();
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
488 innerXRadius = SkMaxScalar(0, xRadius - scaledStroke.fX); 489 innerXRadius = SkMaxScalar(0, xRadius - scaledStroke.fX);
489 innerRatio = innerXRadius/innerYRadius; 490 innerRatio = innerXRadius/innerYRadius;
490 } 491 }
491 } 492 }
492 xRadius += scaledStroke.fX; 493 xRadius += scaledStroke.fX;
493 yRadius += scaledStroke.fY; 494 yRadius += scaledStroke.fY;
494 } 495 }
495 496
496 SkScalar outerRatio = SkScalarDiv(xRadius, yRadius); 497 SkScalar outerRatio = SkScalarDiv(xRadius, yRadius);
497 498
498 for (int i = 0; i < 4; ++i) { 499 // We've extended the outer x radius out half a pixel to antialias.
499 verts[i].fCenter = center; 500 // This will also expand the rect so all the pixels will be captured.
500 verts[i].fOuterXRadius = xRadius + 0.5f; 501 xRadius += SK_ScalarHalf;
501 verts[i].fOuterXYRatio = outerRatio; 502 yRadius += SK_ScalarHalf;
502 verts[i].fInnerXRadius = innerXRadius - 0.5f; 503 innerXRadius -= SK_ScalarHalf;
503 verts[i].fInnerXYRatio = innerRatio;
504 }
505 504
506 SkScalar L = -xRadius; 505 SkRect bounds = SkRect::MakeLTRB(
507 SkScalar R = +xRadius; 506 center.fX - xRadius,
508 SkScalar T = -yRadius; 507 center.fY - yRadius,
509 SkScalar B = +yRadius; 508 center.fX + xRadius,
509 center.fY + yRadius
510 );
510 511
511 // We've extended the outer x radius out half a pixel to antialias. 512 // The offsets are created by scaling the y radius by the appropriate ratio. This way we end up
512 // Expand the drawn rect here so all the pixels will be captured. 513 // with a circle equation which can be checked quickly in the shader. We nee d one offset for
513 L += center.fX - SK_ScalarHalf; 514 // outer and one for inner because they have different scale factors -- othe rwise we end up with
514 R += center.fX + SK_ScalarHalf; 515 // non-uniform strokes.
515 T += center.fY - SK_ScalarHalf; 516 verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop);
516 B += center.fY + SK_ScalarHalf; 517 verts[0].fOuterXRadius = xRadius;
518 verts[0].fInnerXRadius = innerXRadius;
519 verts[0].fOuterOffset = SkPoint::Make(-xRadius, -outerRatio*yRadius);
520 verts[0].fInnerOffset = SkPoint::Make(-xRadius, -innerRatio*yRadius);
517 521
518 verts[0].fPos = SkPoint::Make(L, T); 522 verts[1].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
519 verts[1].fPos = SkPoint::Make(R, T); 523 verts[1].fOuterXRadius = xRadius;
520 verts[2].fPos = SkPoint::Make(L, B); 524 verts[1].fInnerXRadius = innerXRadius;
521 verts[3].fPos = SkPoint::Make(R, B); 525 verts[1].fOuterOffset = SkPoint::Make(xRadius, -outerRatio*yRadius);
526 verts[1].fInnerOffset = SkPoint::Make(xRadius, -innerRatio*yRadius);
522 527
523 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4); 528 verts[2].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom);
529 verts[2].fOuterXRadius = xRadius;
530 verts[2].fInnerXRadius = innerXRadius;
531 verts[2].fOuterOffset = SkPoint::Make(-xRadius, outerRatio*yRadius);
532 verts[2].fInnerOffset = SkPoint::Make(-xRadius, innerRatio*yRadius);
533
534 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
535 verts[3].fOuterXRadius = xRadius;
536 verts[3].fInnerXRadius = innerXRadius;
537 verts[3].fOuterOffset = SkPoint::Make(xRadius, outerRatio*yRadius);
538 verts[3].fInnerOffset = SkPoint::Make(xRadius, innerRatio*yRadius);
539
robertphillips 2013/04/10 23:18:39 For the rect edge passing the bounds actually slow
540 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds);
524 } 541 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698