Chromium Code Reviews| 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 |