 Chromium Code Reviews
 Chromium Code Reviews Issue 22486003:
  Fix hairline pathrenderer for Nexus-10. Switches to passing in an offset and using that to compute …  (Closed) 
  Base URL: https://skia.googlecode.com/svn/trunk
    
  
    Issue 22486003:
  Fix hairline pathrenderer for Nexus-10. Switches to passing in an offset and using that to compute …  (Closed) 
  Base URL: https://skia.googlecode.com/svn/trunk| 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 |