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

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

Issue 761593006: Do circle anti-aliasing in normalized space to avoid precision issues with half-floats on Adreno. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Add ignored tests Created 6 years 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
« no previous file with comments | « gm/circles.cpp ('k') | 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 "GrProcessor.h" 10 #include "GrProcessor.h"
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
46 46
47 inline bool circle_stays_circle(const SkMatrix& m) { 47 inline bool circle_stays_circle(const SkMatrix& m) {
48 return m.isSimilarity(); 48 return m.isSimilarity();
49 } 49 }
50 50
51 } 51 }
52 52
53 /////////////////////////////////////////////////////////////////////////////// 53 ///////////////////////////////////////////////////////////////////////////////
54 54
55 /** 55 /**
56 * The output of this effect is a modulation of the input color and coverage for a circle, 56 * The output of this effect is a modulation of the input color and coverage for a circle. It
57 * specified as offset_x, offset_y (both from center point), outer radius and in ner radius. 57 * operates in a space normalized by the circle radius (outer radius in the case of a stroke)
58 * with origin at the circle center. Two vertex attributes are used:
59 * vec2f : position in device space of the bounding geometry vertices
60 * vec4f : (p.xy, outerRad, innerRad)
61 * p is the position in the normalized space.
62 * outerRad is the outerRadius in device space.
63 * innerRad is the innerRadius in normalized space (ignored if not s troking).
58 */ 64 */
59 65
60 class CircleEdgeEffect : public GrGeometryProcessor { 66 class CircleEdgeEffect : public GrGeometryProcessor {
61 public: 67 public:
62 static GrGeometryProcessor* Create(GrColor color, bool stroke) { 68 static GrGeometryProcessor* Create(GrColor color, bool stroke) {
63 return SkNEW_ARGS(CircleEdgeEffect, (color, stroke)); 69 return SkNEW_ARGS(CircleEdgeEffect, (color, stroke));
64 } 70 }
65 71
66 const GrAttribute* inPosition() const { return fInPosition; } 72 const GrAttribute* inPosition() const { return fInPosition; }
67 const GrAttribute* inCircleEdge() const { return fInCircleEdge; } 73 const GrAttribute* inCircleEdge() const { return fInCircleEdge; }
(...skipping 19 matching lines...) Expand all
87 // setup coord outputs 93 // setup coord outputs
88 vsBuilder->codeAppendf("%s = %s;", vsBuilder->positionCoords(), ce.i nPosition()->fName); 94 vsBuilder->codeAppendf("%s = %s;", vsBuilder->positionCoords(), ce.i nPosition()->fName);
89 vsBuilder->codeAppendf("%s = %s;", vsBuilder->localCoords(), ce.inPo sition()->fName); 95 vsBuilder->codeAppendf("%s = %s;", vsBuilder->localCoords(), ce.inPo sition()->fName);
90 96
91 // setup position varying 97 // setup position varying
92 vsBuilder->codeAppendf("%s = %s * vec3(%s, 1);", vsBuilder->glPositi on(), 98 vsBuilder->codeAppendf("%s = %s * vec3(%s, 1);", vsBuilder->glPositi on(),
93 vsBuilder->uViewM(), ce.inPosition()->fName); 99 vsBuilder->uViewM(), ce.inPosition()->fName);
94 100
95 GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilde r(); 101 GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilde r();
96 fsBuilder->codeAppendf("float d = length(%s.xy);", v.fsIn()); 102 fsBuilder->codeAppendf("float d = length(%s.xy);", v.fsIn());
97 fsBuilder->codeAppendf("float edgeAlpha = clamp(%s.z - d, 0.0, 1.0); ", v.fsIn()); 103 fsBuilder->codeAppendf("float edgeAlpha = clamp(%s.z * (1.0 - d), 0. 0, 1.0);", v.fsIn());
98 if (ce.isStroked()) { 104 if (ce.isStroked()) {
99 fsBuilder->codeAppendf("float innerAlpha = clamp(d - %s.w, 0.0, 1.0);", 105 fsBuilder->codeAppendf("float innerAlpha = clamp(%s.z * (d - %s. w), 0.0, 1.0);",
100 v.fsIn()); 106 v.fsIn(), v.fsIn());
101 fsBuilder->codeAppend("edgeAlpha *= innerAlpha;"); 107 fsBuilder->codeAppend("edgeAlpha *= innerAlpha;");
102 } 108 }
103 109
104 fsBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage ); 110 fsBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage );
105 } 111 }
106 112
107 static void GenKey(const GrGeometryProcessor& processor, 113 static void GenKey(const GrGeometryProcessor& processor,
108 const GrBatchTracker&, 114 const GrBatchTracker&,
109 const GrGLCaps&, 115 const GrGLCaps&,
110 GrProcessorKeyBuilder* b) { 116 GrProcessorKeyBuilder* b) {
(...skipping 456 matching lines...) Expand 10 before | Expand all | Expand 10 after
567 573
568 GrDrawTarget::AutoReleaseGeometry geo(target, 4, gp->getVertexStride(), 0); 574 GrDrawTarget::AutoReleaseGeometry geo(target, 4, gp->getVertexStride(), 0);
569 SkASSERT(gp->getVertexStride() == sizeof(CircleVertex)); 575 SkASSERT(gp->getVertexStride() == sizeof(CircleVertex));
570 if (!geo.succeeded()) { 576 if (!geo.succeeded()) {
571 SkDebugf("Failed to get space for vertices!\n"); 577 SkDebugf("Failed to get space for vertices!\n");
572 return; 578 return;
573 } 579 }
574 580
575 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices()); 581 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices());
576 582
577 // The radii are outset for two reasons. First, it allows the shader to simp ly perform 583 // The radii are outset for two reasons. First, it allows the shader to simp ly perform simpler
578 // clamp(distance-to-center - radius, 0, 1). Second, the outer radius is use d to compute the 584 // computation because the computed alpha is zero, rather than 50%, at the r adius.
579 // verts of the bounding box that is rendered and the outset ensures the box will cover all 585 // Second, the outer radius is used to compute the verts of the bounding box that is rendered
580 // pixels partially covered by the circle. 586 // and the outset ensures the box will cover all partially covered by the ci rcle.
581 outerRadius += SK_ScalarHalf; 587 outerRadius += SK_ScalarHalf;
582 innerRadius -= SK_ScalarHalf; 588 innerRadius -= SK_ScalarHalf;
583 589
584 SkRect bounds = SkRect::MakeLTRB( 590 SkRect bounds = SkRect::MakeLTRB(
585 center.fX - outerRadius, 591 center.fX - outerRadius,
586 center.fY - outerRadius, 592 center.fY - outerRadius,
587 center.fX + outerRadius, 593 center.fX + outerRadius,
588 center.fY + outerRadius 594 center.fY + outerRadius
589 ); 595 );
590 596
597 // The inner radius in the vertex data must be specified in normalized space .
598 innerRadius = innerRadius / outerRadius;
591 verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop); 599 verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop);
592 verts[0].fOffset = SkPoint::Make(-outerRadius, -outerRadius); 600 verts[0].fOffset = SkPoint::Make(-1, -1);
593 verts[0].fOuterRadius = outerRadius; 601 verts[0].fOuterRadius = outerRadius;
594 verts[0].fInnerRadius = innerRadius; 602 verts[0].fInnerRadius = innerRadius;
595 603
596 verts[1].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom); 604 verts[1].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom);
597 verts[1].fOffset = SkPoint::Make(-outerRadius, outerRadius); 605 verts[1].fOffset = SkPoint::Make(-1, 1);
598 verts[1].fOuterRadius = outerRadius; 606 verts[1].fOuterRadius = outerRadius;
599 verts[1].fInnerRadius = innerRadius; 607 verts[1].fInnerRadius = innerRadius;
600 608
601 verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom); 609 verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
602 verts[2].fOffset = SkPoint::Make(outerRadius, outerRadius); 610 verts[2].fOffset = SkPoint::Make(1, 1);
603 verts[2].fOuterRadius = outerRadius; 611 verts[2].fOuterRadius = outerRadius;
604 verts[2].fInnerRadius = innerRadius; 612 verts[2].fInnerRadius = innerRadius;
605 613
606 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop); 614 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
607 verts[3].fOffset = SkPoint::Make(outerRadius, -outerRadius); 615 verts[3].fOffset = SkPoint::Make(1, -1);
608 verts[3].fOuterRadius = outerRadius; 616 verts[3].fOuterRadius = outerRadius;
609 verts[3].fInnerRadius = innerRadius; 617 verts[3].fInnerRadius = innerRadius;
610 618
611 target->setIndexSourceToBuffer(context->getGpu()->getQuadIndexBuffer()); 619 target->setIndexSourceToBuffer(context->getGpu()->getQuadIndexBuffer());
612 target->drawIndexedInstances(drawState, kTriangles_GrPrimitiveType, 1, 4, 6, &bounds); 620 target->drawIndexedInstances(drawState, kTriangles_GrPrimitiveType, 1, 4, 6, &bounds);
613 target->resetIndexSource(); 621 target->resetIndexSource();
614 } 622 }
615 623
616 /////////////////////////////////////////////////////////////////////////////// 624 ///////////////////////////////////////////////////////////////////////////////
617 625
(...skipping 464 matching lines...) Expand 10 before | Expand all | Expand 10 after
1082 1090
1083 GrDrawTarget::AutoReleaseGeometry geo(target, 16, effect->getVertexStrid e(), 0); 1091 GrDrawTarget::AutoReleaseGeometry geo(target, 16, effect->getVertexStrid e(), 0);
1084 SkASSERT(effect->getVertexStride() == sizeof(CircleVertex)); 1092 SkASSERT(effect->getVertexStride() == sizeof(CircleVertex));
1085 if (!geo.succeeded()) { 1093 if (!geo.succeeded()) {
1086 SkDebugf("Failed to get space for vertices!\n"); 1094 SkDebugf("Failed to get space for vertices!\n");
1087 return false; 1095 return false;
1088 } 1096 }
1089 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices()); 1097 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices());
1090 1098
1091 // The radii are outset for two reasons. First, it allows the shader to simply perform 1099 // The radii are outset for two reasons. First, it allows the shader to simply perform
1092 // clamp(distance-to-center - radius, 0, 1). Second, the outer radius is used to compute the 1100 // simpler computation because the computed alpha is zero, rather than 5 0%, at the radius.
1093 // verts of the bounding box that is rendered and the outset ensures the box will cover all 1101 // Second, the outer radius is used to compute the verts of the bounding box that is
1094 // pixels partially covered by the circle. 1102 // rendered and the outset ensures the box will cover all partially cove red by the rrect
1103 // corners.
1095 outerRadius += SK_ScalarHalf; 1104 outerRadius += SK_ScalarHalf;
1096 innerRadius -= SK_ScalarHalf; 1105 innerRadius -= SK_ScalarHalf;
1097 1106
1098 // Expand the rect so all the pixels will be captured. 1107 // Expand the rect so all the pixels will be captured.
1099 bounds.outset(SK_ScalarHalf, SK_ScalarHalf); 1108 bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
1100 1109
1101 SkScalar yCoords[4] = { 1110 SkScalar yCoords[4] = {
1102 bounds.fTop, 1111 bounds.fTop,
1103 bounds.fTop + outerRadius, 1112 bounds.fTop + outerRadius,
1104 bounds.fBottom - outerRadius, 1113 bounds.fBottom - outerRadius,
1105 bounds.fBottom 1114 bounds.fBottom
1106 }; 1115 };
1107 SkScalar yOuterRadii[4] = { 1116 SkScalar yOuterRadii[4] = {-1, 0, 0, 1 };
1108 -outerRadius, 1117 // The inner radius in the vertex data must be specified in normalized s pace.
1109 0, 1118 innerRadius = innerRadius / outerRadius;
1110 0,
1111 outerRadius
1112 };
1113 for (int i = 0; i < 4; ++i) { 1119 for (int i = 0; i < 4; ++i) {
1114 verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]); 1120 verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]);
1115 verts->fOffset = SkPoint::Make(-outerRadius, yOuterRadii[i]); 1121 verts->fOffset = SkPoint::Make(-1, yOuterRadii[i]);
1116 verts->fOuterRadius = outerRadius; 1122 verts->fOuterRadius = outerRadius;
1117 verts->fInnerRadius = innerRadius; 1123 verts->fInnerRadius = innerRadius;
1118 verts++; 1124 verts++;
1119 1125
1120 verts->fPos = SkPoint::Make(bounds.fLeft + outerRadius, yCoords[i]); 1126 verts->fPos = SkPoint::Make(bounds.fLeft + outerRadius, yCoords[i]);
1121 verts->fOffset = SkPoint::Make(0, yOuterRadii[i]); 1127 verts->fOffset = SkPoint::Make(0, yOuterRadii[i]);
1122 verts->fOuterRadius = outerRadius; 1128 verts->fOuterRadius = outerRadius;
1123 verts->fInnerRadius = innerRadius; 1129 verts->fInnerRadius = innerRadius;
1124 verts++; 1130 verts++;
1125 1131
1126 verts->fPos = SkPoint::Make(bounds.fRight - outerRadius, yCoords[i]) ; 1132 verts->fPos = SkPoint::Make(bounds.fRight - outerRadius, yCoords[i]) ;
1127 verts->fOffset = SkPoint::Make(0, yOuterRadii[i]); 1133 verts->fOffset = SkPoint::Make(0, yOuterRadii[i]);
1128 verts->fOuterRadius = outerRadius; 1134 verts->fOuterRadius = outerRadius;
1129 verts->fInnerRadius = innerRadius; 1135 verts->fInnerRadius = innerRadius;
1130 verts++; 1136 verts++;
1131 1137
1132 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]); 1138 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]);
1133 verts->fOffset = SkPoint::Make(outerRadius, yOuterRadii[i]); 1139 verts->fOffset = SkPoint::Make(1, yOuterRadii[i]);
1134 verts->fOuterRadius = outerRadius; 1140 verts->fOuterRadius = outerRadius;
1135 verts->fInnerRadius = innerRadius; 1141 verts->fInnerRadius = innerRadius;
1136 verts++; 1142 verts++;
1137 } 1143 }
1138 1144
1139 // drop out the middle quad if we're stroked 1145 // drop out the middle quad if we're stroked
1140 int indexCnt = isStrokeOnly ? SK_ARRAY_COUNT(gRRectIndices) - 6 : 1146 int indexCnt = isStrokeOnly ? SK_ARRAY_COUNT(gRRectIndices) - 6 :
1141 SK_ARRAY_COUNT(gRRectIndices); 1147 SK_ARRAY_COUNT(gRRectIndices);
1142 target->setIndexSourceToBuffer(indexBuffer); 1148 target->setIndexSourceToBuffer(indexBuffer);
1143 target->drawIndexedInstances(drawState, kTriangles_GrPrimitiveType, 1, 1 6, indexCnt, 1149 target->drawIndexedInstances(drawState, kTriangles_GrPrimitiveType, 1, 1 6, indexCnt,
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
1247 int indexCnt = isStrokeOnly ? SK_ARRAY_COUNT(gRRectIndices) - 6 : 1253 int indexCnt = isStrokeOnly ? SK_ARRAY_COUNT(gRRectIndices) - 6 :
1248 SK_ARRAY_COUNT(gRRectIndices); 1254 SK_ARRAY_COUNT(gRRectIndices);
1249 target->setIndexSourceToBuffer(indexBuffer); 1255 target->setIndexSourceToBuffer(indexBuffer);
1250 target->drawIndexedInstances(drawState, kTriangles_GrPrimitiveType, 1, 1 6, indexCnt, 1256 target->drawIndexedInstances(drawState, kTriangles_GrPrimitiveType, 1, 1 6, indexCnt,
1251 &bounds); 1257 &bounds);
1252 } 1258 }
1253 1259
1254 target->resetIndexSource(); 1260 target->resetIndexSource();
1255 return true; 1261 return true;
1256 } 1262 }
OLDNEW
« no previous file with comments | « gm/circles.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698