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 | |
robertphillips
2013/08/08 13:08:54
make this static too?
jvanverth1
2013/08/08 18:09:48
Done.
| |
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 | |
robertphillips
2013/08/08 13:08:54
static - given the name?
qIdxBuffer -> lineIdxBuff
jvanverth1
2013/08/08 18:09:48
Done.
| |
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 | |
robertphillips
2013/08/08 13:08:54
i.e.,
jvanverth1
2013/08/08 18:09:48
Done.
| |
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); | |
robertphillips
2013/08/08 13:08:54
Make one line?
jvanverth1
2013/08/08 18:09:48
Done.
| |
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 322 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 struct { |
439 SkScalar fA; | 490 SkScalar fCoverage; |
440 SkScalar fB; | |
441 SkScalar fC; | |
442 } fLine; | 491 } fLine; |
443 struct { | 492 struct { |
444 SkScalar fK; | 493 SkScalar fK; |
445 SkScalar fL; | 494 SkScalar fL; |
446 SkScalar fM; | 495 SkScalar fM; |
447 } fConic; | 496 } fConic; |
448 GrVec fQuadCoord; | 497 GrVec fQuadCoord; |
449 struct { | 498 struct { |
450 SkScalar fBogus[4]; | 499 SkScalar fBogus[4]; |
451 }; | 500 }; |
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
654 Vertex** vert) { | 703 Vertex** vert) { |
655 const SkPoint& a = p[0]; | 704 const SkPoint& a = p[0]; |
656 const SkPoint& b = p[1]; | 705 const SkPoint& b = p[1]; |
657 | 706 |
658 SkVector orthVec = b; | 707 SkVector orthVec = b; |
659 orthVec -= a; | 708 orthVec -= a; |
660 | 709 |
661 if (orthVec.setLength(SK_Scalar1)) { | 710 if (orthVec.setLength(SK_Scalar1)) { |
662 orthVec.setOrthog(orthVec); | 711 orthVec.setOrthog(orthVec); |
663 | 712 |
664 SkScalar lineC = -(a.dot(orthVec)); | |
665 for (int i = 0; i < kVertsPerLineSeg; ++i) { | 713 for (int i = 0; i < kVertsPerLineSeg; ++i) { |
666 (*vert)[i].fPos = (i < 2) ? a : b; | 714 (*vert)[i].fPos = (i & 0x1) ? b : a; |
667 if (0 == i || 3 == i) { | 715 if (i & 0x2) { |
716 (*vert)[i].fPos += orthVec; | |
717 (*vert)[i].fLine.fCoverage = 0; | |
718 } else if (i & 0x4) { | |
668 (*vert)[i].fPos -= orthVec; | 719 (*vert)[i].fPos -= orthVec; |
720 (*vert)[i].fLine.fCoverage = 0; | |
669 } else { | 721 } else { |
670 (*vert)[i].fPos += orthVec; | 722 (*vert)[i].fLine.fCoverage = SK_Scalar1; |
671 } | 723 } |
672 (*vert)[i].fLine.fA = orthVec.fX; | |
673 (*vert)[i].fLine.fB = orthVec.fY; | |
674 (*vert)[i].fLine.fC = lineC; | |
675 } | 724 } |
676 if (NULL != toSrc) { | 725 if (NULL != toSrc) { |
677 toSrc->mapPointsWithStride(&(*vert)->fPos, | 726 toSrc->mapPointsWithStride(&(*vert)->fPos, |
678 sizeof(Vertex), | 727 sizeof(Vertex), |
679 kVertsPerLineSeg); | 728 kVertsPerLineSeg); |
680 } | 729 } |
681 } else { | 730 } else { |
682 // just make it degenerate and likely offscreen | 731 // just make it degenerate and likely offscreen |
683 (*vert)[0].fPos.set(SK_ScalarMax, SK_ScalarMax); | 732 (*vert)[0].fPos.set(SK_ScalarMax, SK_ScalarMax); |
684 (*vert)[1].fPos.set(SK_ScalarMax, SK_ScalarMax); | 733 (*vert)[1].fPos.set(SK_ScalarMax, SK_ScalarMax); |
685 (*vert)[2].fPos.set(SK_ScalarMax, SK_ScalarMax); | 734 (*vert)[2].fPos.set(SK_ScalarMax, SK_ScalarMax); |
686 (*vert)[3].fPos.set(SK_ScalarMax, SK_ScalarMax); | 735 (*vert)[3].fPos.set(SK_ScalarMax, SK_ScalarMax); |
736 (*vert)[4].fPos.set(SK_ScalarMax, SK_ScalarMax); | |
737 (*vert)[5].fPos.set(SK_ScalarMax, SK_ScalarMax); | |
687 } | 738 } |
688 | 739 |
689 *vert += kVertsPerLineSeg; | 740 *vert += kVertsPerLineSeg; |
690 } | 741 } |
691 | 742 |
692 } | 743 } |
693 | 744 |
694 /** | 745 /** |
695 * Shader is based off of Loop-Blinn Quadratic GPU Rendering | 746 * Shader is based off of Loop-Blinn Quadratic GPU Rendering |
696 * The output of this effect is a hairline edge for conics. | 747 * 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, | 980 const GrDrawTargetCaps& caps, |
930 GrTexture*[]) { | 981 GrTexture*[]) { |
931 // Doesn't work without derivative instructions. | 982 // Doesn't work without derivative instructions. |
932 return caps.shaderDerivativeSupport() ? HairQuadEdgeEffect::Create() : NULL; | 983 return caps.shaderDerivativeSupport() ? HairQuadEdgeEffect::Create() : NULL; |
933 } | 984 } |
934 | 985 |
935 /////////////////////////////////////////////////////////////////////////////// | 986 /////////////////////////////////////////////////////////////////////////////// |
936 | 987 |
937 /** | 988 /** |
938 * The output of this effect is a 1-pixel wide line. | 989 * 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. | 990 * Input is coverage relative to the line. |
940 */ | 991 */ |
941 class HairLineEdgeEffect : public GrEffect { | 992 class HairLineEdgeEffect : public GrEffect { |
942 public: | 993 public: |
943 | 994 |
944 static GrEffectRef* Create() { | 995 static GrEffectRef* Create() { |
945 GR_CREATE_STATIC_EFFECT(gHairLineEdge, HairLineEdgeEffect, ()); | 996 GR_CREATE_STATIC_EFFECT(gHairLineEdge, HairLineEdgeEffect, ()); |
946 gHairLineEdge->ref(); | 997 gHairLineEdge->ref(); |
947 return gHairLineEdge; | 998 return gHairLineEdge; |
948 } | 999 } |
949 | 1000 |
(...skipping 21 matching lines...) Expand all Loading... | |
971 const char* outputColor, | 1022 const char* outputColor, |
972 const char* inputColor, | 1023 const char* inputColor, |
973 const TextureSamplerArray& samplers) SK_OVERRIDE { | 1024 const TextureSamplerArray& samplers) SK_OVERRIDE { |
974 const char *vsName, *fsName; | 1025 const char *vsName, *fsName; |
975 const SkString* attrName = | 1026 const SkString* attrName = |
976 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[0]); | 1027 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[0]); |
977 builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n"); | 1028 builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n"); |
978 | 1029 |
979 builder->addVarying(kVec4f_GrSLType, "HairLineEdge", &vsName, &fsNam e); | 1030 builder->addVarying(kVec4f_GrSLType, "HairLineEdge", &vsName, &fsNam e); |
980 | 1031 |
981 builder->fsCodeAppendf("\t\tedgeAlpha = abs(dot(vec3(%s.xy,1), %s.xy z));\n", | 1032 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 | 1033 |
985 SkString modulate; | 1034 SkString modulate; |
986 GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha"); | 1035 GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha"); |
987 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str() ); | 1036 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str() ); |
988 | 1037 |
989 builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str()); | 1038 builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str()); |
990 } | 1039 } |
991 | 1040 |
992 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrG LCaps&) { | 1041 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrG LCaps&) { |
993 return 0x0; | 1042 return 0x0; |
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1184 } else { | 1233 } else { |
1185 actualBounds.growToInclude(pos.fX, pos.fY); | 1234 actualBounds.growToInclude(pos.fX, pos.fY); |
1186 } | 1235 } |
1187 } | 1236 } |
1188 if (!first) { | 1237 if (!first) { |
1189 GrAssert(tolDevBounds.contains(actualBounds)); | 1238 GrAssert(tolDevBounds.contains(actualBounds)); |
1190 } | 1239 } |
1191 #endif | 1240 #endif |
1192 | 1241 |
1193 { | 1242 { |
1243 // the fact we're using an effect to pass per-vertex coverage is kind of dumb, | |
1244 // but necessary due to the shared vertex buffer | |
1245 // TODO: refactor so that we render lines with a separate vertex buffer | |
1194 GrDrawState::AutoRestoreEffects are(drawState); | 1246 GrDrawState::AutoRestoreEffects are(drawState); |
1195 target->setIndexSourceToBuffer(fLinesIndexBuffer); | 1247 target->setIndexSourceToBuffer(fLinesIndexBuffer); |
1196 int lines = 0; | 1248 int lines = 0; |
1197 int nBufLines = fLinesIndexBuffer->maxQuads(); | |
1198 drawState->addCoverageEffect(hairLineEffect, kEdgeAttrIndex)->unref(); | 1249 drawState->addCoverageEffect(hairLineEffect, kEdgeAttrIndex)->unref(); |
1199 while (lines < lineCnt) { | 1250 while (lines < lineCnt) { |
1200 int n = GrMin(lineCnt - lines, nBufLines); | 1251 int n = GrMin(lineCnt - lines, kNumLineSegsInIdxBuffer); |
1201 target->drawIndexed(kTriangles_GrPrimitiveType, | 1252 target->drawIndexed(kTriangles_GrPrimitiveType, |
1202 kVertsPerLineSeg*lines, // startV | 1253 kVertsPerLineSeg*lines, // startV |
1203 0, // startI | 1254 0, // startI |
1204 kVertsPerLineSeg*n, // vCount | 1255 kVertsPerLineSeg*n, // vCount |
1205 kIdxsPerLineSeg*n, | 1256 kIdxsPerLineSeg*n, |
1206 &devBounds); // iCount | 1257 &devBounds); // iCount |
1207 lines += n; | 1258 lines += n; |
1208 } | 1259 } |
1209 } | 1260 } |
1210 | 1261 |
(...skipping 27 matching lines...) Expand all Loading... | |
1238 kVertsPerQuad*n, // vCount | 1289 kVertsPerQuad*n, // vCount |
1239 kIdxsPerQuad*n, // iCount | 1290 kIdxsPerQuad*n, // iCount |
1240 &devBounds); | 1291 &devBounds); |
1241 conics += n; | 1292 conics += n; |
1242 } | 1293 } |
1243 } | 1294 } |
1244 target->resetIndexSource(); | 1295 target->resetIndexSource(); |
1245 | 1296 |
1246 return true; | 1297 return true; |
1247 } | 1298 } |
OLD | NEW |