OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 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 "GrAAHairLinePathRenderer.h" | 8 #include "GrAAHairLinePathRenderer.h" |
9 | 9 |
10 #include "GrContext.h" | 10 #include "GrContext.h" |
(...skipping 11 matching lines...) Expand all Loading... | |
22 #include "gl/GrGLEffect.h" | 22 #include "gl/GrGLEffect.h" |
23 #include "gl/GrGLSL.h" | 23 #include "gl/GrGLSL.h" |
24 | 24 |
25 namespace { | 25 namespace { |
26 // quadratics are rendered as 5-sided polys in order to bound the | 26 // quadratics are rendered as 5-sided polys in order to bound the |
27 // AA stroke around the center-curve. See comments in push_quad_index_buffer and | 27 // AA stroke around the center-curve. See comments in push_quad_index_buffer and |
28 // bloat_quad. Quadratics and conics share an index buffer | 28 // bloat_quad. Quadratics and conics share an index buffer |
29 static const int kVertsPerQuad = 5; | 29 static const int kVertsPerQuad = 5; |
30 static const int kIdxsPerQuad = 9; | 30 static const int kIdxsPerQuad = 9; |
31 | 31 |
32 static const int kVertsPerLineSeg = 4; | 32 static const int kVertsPerLineSeg = 6; |
33 static const int kIdxsPerLineSeg = 6; | 33 static const int kIdxsPerLineSeg = 12; |
34 | 34 |
35 static const int kNumQuadsInIdxBuffer = 256; | 35 static const int kNumQuadsInIdxBuffer = 256; |
36 static const size_t kQuadIdxSBufize = kIdxsPerQuad * | 36 static const size_t kQuadIdxSBufize = kIdxsPerQuad * |
37 sizeof(uint16_t) * | 37 sizeof(uint16_t) * |
38 kNumQuadsInIdxBuffer; | 38 kNumQuadsInIdxBuffer; |
39 | 39 |
40 static const int kNumLineSegsInIdxBuffer = 256; | |
41 static const size_t kLineSegIdxSBufize = kIdxsPerLineSeg * | |
42 sizeof(uint16_t) * | |
43 kNumLineSegsInIdxBuffer; | |
44 | |
40 bool push_quad_index_data(GrIndexBuffer* qIdxBuffer) { | 45 bool push_quad_index_data(GrIndexBuffer* qIdxBuffer) { |
41 uint16_t* data = (uint16_t*) qIdxBuffer->lock(); | 46 uint16_t* data = (uint16_t*) qIdxBuffer->lock(); |
42 bool tempData = NULL == data; | 47 bool tempData = NULL == data; |
43 if (tempData) { | 48 if (tempData) { |
44 data = SkNEW_ARRAY(uint16_t, kNumQuadsInIdxBuffer * kIdxsPerQuad); | 49 data = SkNEW_ARRAY(uint16_t, kNumQuadsInIdxBuffer * kIdxsPerQuad); |
45 } | 50 } |
46 for (int i = 0; i < kNumQuadsInIdxBuffer; ++i) { | 51 for (int i = 0; i < kNumQuadsInIdxBuffer; ++i) { |
47 | 52 |
48 // Each quadratic is rendered as a five sided polygon. This poly bounds | 53 // Each quadratic is rendered as a five sided polygon. This poly bounds |
49 // the quadratic's bounding triangle but has been expanded so that the | 54 // the quadratic's bounding triangle but has been expanded so that the |
(...skipping 21 matching lines...) Expand all Loading... | |
71 } | 76 } |
72 if (tempData) { | 77 if (tempData) { |
73 bool ret = qIdxBuffer->updateData(data, kQuadIdxSBufize); | 78 bool ret = qIdxBuffer->updateData(data, kQuadIdxSBufize); |
74 delete[] data; | 79 delete[] data; |
75 return ret; | 80 return ret; |
76 } else { | 81 } else { |
77 qIdxBuffer->unlock(); | 82 qIdxBuffer->unlock(); |
78 return true; | 83 return true; |
79 } | 84 } |
80 } | 85 } |
86 | |
87 bool push_line_index_data(GrIndexBuffer* qIdxBuffer) { | |
88 uint16_t* data = (uint16_t*) qIdxBuffer->lock(); | |
89 bool tempData = NULL == data; | |
90 if (tempData) { | |
91 data = SkNEW_ARRAY(uint16_t, kNumLineSegsInIdxBuffer * kIdxsPerLineSeg); | |
92 } | |
93 for (int i = 0; i < kNumLineSegsInIdxBuffer; ++i) { | |
94 // Each line segment is rendered as two quads, with alpha = 1 along the | |
95 // spine of the segment, and alpha = 0 along the outer edges, represente d | |
96 // horizontally like (i.e. the line equation is t*(p1-p0) + p0) | |
97 // | |
98 // p4 p5 | |
99 // p0 p1 | |
100 // p2 p3 | |
101 // | |
102 // Each is drawn as four triangles specified by these 12 indices: | |
103 int baseIdx = i * kIdxsPerLineSeg; | |
104 uint16_t baseVert = (uint16_t)(i * kVertsPerLineSeg); | |
105 data[0 + baseIdx] = baseVert + 0; // p0 | |
106 data[1 + baseIdx] = baseVert + 1; // p1 | |
107 data[2 + baseIdx] = baseVert + 2; // p2 | |
108 | |
109 data[3 + baseIdx] = baseVert + 2; // p2 | |
110 data[4 + baseIdx] = baseVert + 1; // p1 | |
111 data[5 + baseIdx] = baseVert + 3; // p3 | |
112 | |
113 data[6 + baseIdx] = baseVert + 0; // p0 | |
114 data[7 + baseIdx] = baseVert + 5; // p5 | |
115 data[8 + baseIdx] = baseVert + 1; // p1 | |
116 | |
117 data[9 + baseIdx] = baseVert + 0; // p0 | |
118 data[10+ baseIdx] = baseVert + 4; // p4 | |
119 data[11+ baseIdx] = baseVert + 5; // p5 | |
120 } | |
121 if (tempData) { | |
122 bool ret = qIdxBuffer->updateData(data, kLineSegIdxSBufize); | |
123 delete[] data; | |
124 return ret; | |
125 } else { | |
126 qIdxBuffer->unlock(); | |
127 return true; | |
128 } | |
129 } | |
81 } | 130 } |
82 | 131 |
83 GrPathRenderer* GrAAHairLinePathRenderer::Create(GrContext* context) { | 132 GrPathRenderer* GrAAHairLinePathRenderer::Create(GrContext* context) { |
84 const GrIndexBuffer* lIdxBuffer = context->getQuadIndexBuffer(); | |
85 if (NULL == lIdxBuffer) { | |
86 return NULL; | |
87 } | |
88 GrGpu* gpu = context->getGpu(); | 133 GrGpu* gpu = context->getGpu(); |
89 GrIndexBuffer* qIdxBuf = gpu->createIndexBuffer(kQuadIdxSBufize, false); | 134 GrIndexBuffer* qIdxBuf = gpu->createIndexBuffer(kQuadIdxSBufize, false); |
90 SkAutoTUnref<GrIndexBuffer> qIdxBuffer(qIdxBuf); | 135 SkAutoTUnref<GrIndexBuffer> qIdxBuffer(qIdxBuf); |
91 if (NULL == qIdxBuf || | 136 if (NULL == qIdxBuf || |
92 !push_quad_index_data(qIdxBuf)) { | 137 !push_quad_index_data(qIdxBuf)) { |
93 return NULL; | 138 return NULL; |
94 } | 139 } |
140 GrIndexBuffer* lIdxBuf = gpu->createIndexBuffer(kLineSegIdxSBufize, false); | |
141 SkAutoTUnref<GrIndexBuffer> lIdxBuffer(lIdxBuf); | |
142 if (NULL == lIdxBuf || | |
143 !push_line_index_data(lIdxBuf)) { | |
144 return NULL; | |
145 } | |
95 return SkNEW_ARGS(GrAAHairLinePathRenderer, | 146 return SkNEW_ARGS(GrAAHairLinePathRenderer, |
96 (context, lIdxBuffer, qIdxBuf)); | 147 (context, lIdxBuf, qIdxBuf)); |
97 } | 148 } |
98 | 149 |
99 GrAAHairLinePathRenderer::GrAAHairLinePathRenderer( | 150 GrAAHairLinePathRenderer::GrAAHairLinePathRenderer( |
100 const GrContext* context, | 151 const GrContext* context, |
101 const GrIndexBuffer* linesIndexBuffer, | 152 const GrIndexBuffer* linesIndexBuffer, |
102 const GrIndexBuffer* quadsIndexBuffer) { | 153 const GrIndexBuffer* quadsIndexBuffer) { |
103 fLinesIndexBuffer = linesIndexBuffer; | 154 fLinesIndexBuffer = linesIndexBuffer; |
104 linesIndexBuffer->ref(); | 155 linesIndexBuffer->ref(); |
105 fQuadsIndexBuffer = quadsIndexBuffer; | 156 fQuadsIndexBuffer = quadsIndexBuffer; |
106 quadsIndexBuffer->ref(); | 157 quadsIndexBuffer->ref(); |
(...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
428 break; | 479 break; |
429 case SkPath::kDone_Verb: | 480 case SkPath::kDone_Verb: |
430 return totalQuadCount; | 481 return totalQuadCount; |
431 } | 482 } |
432 } | 483 } |
433 } | 484 } |
434 | 485 |
435 struct Vertex { | 486 struct Vertex { |
436 GrPoint fPos; | 487 GrPoint fPos; |
437 union { | 488 union { |
438 struct { | 489 SkScalar fCoverage; |
bsalomon
2013/08/07 20:59:57
fLineCoverage? or...
struct {
SkScalar fCoverage
jvanverth1
2013/08/07 21:15:04
Done.
| |
439 SkScalar fA; | |
440 SkScalar fB; | |
441 SkScalar fC; | |
442 } fLine; | |
443 struct { | 490 struct { |
444 SkScalar fK; | 491 SkScalar fK; |
445 SkScalar fL; | 492 SkScalar fL; |
446 SkScalar fM; | 493 SkScalar fM; |
447 } fConic; | 494 } fConic; |
448 GrVec fQuadCoord; | 495 GrVec fQuadCoord; |
449 struct { | 496 struct { |
450 SkScalar fBogus[4]; | 497 SkScalar fBogus[4]; |
451 }; | 498 }; |
452 }; | 499 }; |
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
654 Vertex** vert) { | 701 Vertex** vert) { |
655 const SkPoint& a = p[0]; | 702 const SkPoint& a = p[0]; |
656 const SkPoint& b = p[1]; | 703 const SkPoint& b = p[1]; |
657 | 704 |
658 SkVector orthVec = b; | 705 SkVector orthVec = b; |
659 orthVec -= a; | 706 orthVec -= a; |
660 | 707 |
661 if (orthVec.setLength(SK_Scalar1)) { | 708 if (orthVec.setLength(SK_Scalar1)) { |
662 orthVec.setOrthog(orthVec); | 709 orthVec.setOrthog(orthVec); |
663 | 710 |
664 SkScalar lineC = -(a.dot(orthVec)); | |
665 for (int i = 0; i < kVertsPerLineSeg; ++i) { | 711 for (int i = 0; i < kVertsPerLineSeg; ++i) { |
666 (*vert)[i].fPos = (i < 2) ? a : b; | 712 (*vert)[i].fPos = (i & 0x1) ? b : a; |
667 if (0 == i || 3 == i) { | 713 if (i & 0x2) { |
714 (*vert)[i].fPos += orthVec; | |
715 (*vert)[i].fCoverage = 0; | |
716 } else if (i & 0x4) { | |
668 (*vert)[i].fPos -= orthVec; | 717 (*vert)[i].fPos -= orthVec; |
718 (*vert)[i].fCoverage = 0; | |
669 } else { | 719 } else { |
670 (*vert)[i].fPos += orthVec; | 720 (*vert)[i].fCoverage= SK_Scalar1; |
671 } | 721 } |
672 (*vert)[i].fLine.fA = orthVec.fX; | |
673 (*vert)[i].fLine.fB = orthVec.fY; | |
674 (*vert)[i].fLine.fC = lineC; | |
675 } | 722 } |
676 if (NULL != toSrc) { | 723 if (NULL != toSrc) { |
677 toSrc->mapPointsWithStride(&(*vert)->fPos, | 724 toSrc->mapPointsWithStride(&(*vert)->fPos, |
678 sizeof(Vertex), | 725 sizeof(Vertex), |
679 kVertsPerLineSeg); | 726 kVertsPerLineSeg); |
680 } | 727 } |
681 } else { | 728 } else { |
682 // just make it degenerate and likely offscreen | 729 // just make it degenerate and likely offscreen |
683 (*vert)[0].fPos.set(SK_ScalarMax, SK_ScalarMax); | 730 (*vert)[0].fPos.set(SK_ScalarMax, SK_ScalarMax); |
684 (*vert)[1].fPos.set(SK_ScalarMax, SK_ScalarMax); | 731 (*vert)[1].fPos.set(SK_ScalarMax, SK_ScalarMax); |
685 (*vert)[2].fPos.set(SK_ScalarMax, SK_ScalarMax); | 732 (*vert)[2].fPos.set(SK_ScalarMax, SK_ScalarMax); |
686 (*vert)[3].fPos.set(SK_ScalarMax, SK_ScalarMax); | 733 (*vert)[3].fPos.set(SK_ScalarMax, SK_ScalarMax); |
734 (*vert)[4].fPos.set(SK_ScalarMax, SK_ScalarMax); | |
735 (*vert)[5].fPos.set(SK_ScalarMax, SK_ScalarMax); | |
687 } | 736 } |
688 | 737 |
689 *vert += kVertsPerLineSeg; | 738 *vert += kVertsPerLineSeg; |
690 } | 739 } |
691 | 740 |
692 } | 741 } |
693 | 742 |
694 /** | 743 /** |
695 * Shader is based off of Loop-Blinn Quadratic GPU Rendering | 744 * Shader is based off of Loop-Blinn Quadratic GPU Rendering |
696 * The output of this effect is a hairline edge for conics. | 745 * The output of this effect is a hairline edge for conics. |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
929 const GrDrawTargetCaps& caps, | 978 const GrDrawTargetCaps& caps, |
930 GrTexture*[]) { | 979 GrTexture*[]) { |
931 // Doesn't work without derivative instructions. | 980 // Doesn't work without derivative instructions. |
932 return caps.shaderDerivativeSupport() ? HairQuadEdgeEffect::Create() : NULL; | 981 return caps.shaderDerivativeSupport() ? HairQuadEdgeEffect::Create() : NULL; |
933 } | 982 } |
934 | 983 |
935 /////////////////////////////////////////////////////////////////////////////// | 984 /////////////////////////////////////////////////////////////////////////////// |
936 | 985 |
937 /** | 986 /** |
938 * The output of this effect is a 1-pixel wide line. | 987 * The output of this effect is a 1-pixel wide line. |
939 * Input is 2D implicit device coord line eq (a*x + b*y +c = 0). 4th component u nused. | 988 * Input is 2D offset vector from the line. 3rd and 4th components unused. |
940 */ | 989 */ |
941 class HairLineEdgeEffect : public GrEffect { | 990 class HairLineEdgeEffect : public GrEffect { |
942 public: | 991 public: |
943 | 992 |
944 static GrEffectRef* Create() { | 993 static GrEffectRef* Create() { |
945 GR_CREATE_STATIC_EFFECT(gHairLineEdge, HairLineEdgeEffect, ()); | 994 GR_CREATE_STATIC_EFFECT(gHairLineEdge, HairLineEdgeEffect, ()); |
946 gHairLineEdge->ref(); | 995 gHairLineEdge->ref(); |
947 return gHairLineEdge; | 996 return gHairLineEdge; |
948 } | 997 } |
949 | 998 |
(...skipping 21 matching lines...) Expand all Loading... | |
971 const char* outputColor, | 1020 const char* outputColor, |
972 const char* inputColor, | 1021 const char* inputColor, |
973 const TextureSamplerArray& samplers) SK_OVERRIDE { | 1022 const TextureSamplerArray& samplers) SK_OVERRIDE { |
974 const char *vsName, *fsName; | 1023 const char *vsName, *fsName; |
975 const SkString* attrName = | 1024 const SkString* attrName = |
976 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[0]); | 1025 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[0]); |
977 builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n"); | 1026 builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n"); |
978 | 1027 |
979 builder->addVarying(kVec4f_GrSLType, "HairLineEdge", &vsName, &fsNam e); | 1028 builder->addVarying(kVec4f_GrSLType, "HairLineEdge", &vsName, &fsNam e); |
980 | 1029 |
981 builder->fsCodeAppendf("\t\tedgeAlpha = abs(dot(vec3(%s.xy,1), %s.xy z));\n", | 1030 builder->fsCodeAppendf("\t\tedgeAlpha = %s.x;\n", fsName); |
982 builder->fragmentPosition(), fsName); | |
983 builder->fsCodeAppendf("\t\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n "); | |
984 | 1031 |
985 SkString modulate; | 1032 SkString modulate; |
986 GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha"); | 1033 GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha"); |
987 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str() ); | 1034 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str() ); |
988 | 1035 |
989 builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str()); | 1036 builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str()); |
990 } | 1037 } |
991 | 1038 |
992 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrG LCaps&) { | 1039 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrG LCaps&) { |
993 return 0x0; | 1040 return 0x0; |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1187 } | 1234 } |
1188 if (!first) { | 1235 if (!first) { |
1189 GrAssert(tolDevBounds.contains(actualBounds)); | 1236 GrAssert(tolDevBounds.contains(actualBounds)); |
1190 } | 1237 } |
1191 #endif | 1238 #endif |
1192 | 1239 |
1193 { | 1240 { |
1194 GrDrawState::AutoRestoreEffects are(drawState); | 1241 GrDrawState::AutoRestoreEffects are(drawState); |
1195 target->setIndexSourceToBuffer(fLinesIndexBuffer); | 1242 target->setIndexSourceToBuffer(fLinesIndexBuffer); |
1196 int lines = 0; | 1243 int lines = 0; |
1197 int nBufLines = fLinesIndexBuffer->maxQuads(); | |
1198 drawState->addCoverageEffect(hairLineEffect, kEdgeAttrIndex)->unref(); | 1244 drawState->addCoverageEffect(hairLineEffect, kEdgeAttrIndex)->unref(); |
1199 while (lines < lineCnt) { | 1245 while (lines < lineCnt) { |
1200 int n = GrMin(lineCnt - lines, nBufLines); | 1246 int n = GrMin(lineCnt - lines, kNumLineSegsInIdxBuffer); |
1201 target->drawIndexed(kTriangles_GrPrimitiveType, | 1247 target->drawIndexed(kTriangles_GrPrimitiveType, |
1202 kVertsPerLineSeg*lines, // startV | 1248 kVertsPerLineSeg*lines, // startV |
1203 0, // startI | 1249 0, // startI |
1204 kVertsPerLineSeg*n, // vCount | 1250 kVertsPerLineSeg*n, // vCount |
1205 kIdxsPerLineSeg*n, | 1251 kIdxsPerLineSeg*n, |
1206 &devBounds); // iCount | 1252 &devBounds); // iCount |
1207 lines += n; | 1253 lines += n; |
1208 } | 1254 } |
1209 } | 1255 } |
1210 | 1256 |
(...skipping 27 matching lines...) Expand all Loading... | |
1238 kVertsPerQuad*n, // vCount | 1284 kVertsPerQuad*n, // vCount |
1239 kIdxsPerQuad*n, // iCount | 1285 kIdxsPerQuad*n, // iCount |
1240 &devBounds); | 1286 &devBounds); |
1241 conics += n; | 1287 conics += n; |
1242 } | 1288 } |
1243 } | 1289 } |
1244 target->resetIndexSource(); | 1290 target->resetIndexSource(); |
1245 | 1291 |
1246 return true; | 1292 return true; |
1247 } | 1293 } |
OLD | NEW |