Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 | 1 |
| 2 /* | 2 /* |
| 3 * Copyright 2011 Google Inc. | 3 * Copyright 2011 Google Inc. |
| 4 * | 4 * |
| 5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
| 6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
| 7 */ | 7 */ |
| 8 | 8 |
| 9 #include "GrAAHairLinePathRenderer.h" | 9 #include "GrAAHairLinePathRenderer.h" |
| 10 | 10 |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 23 #include "gl/GrGLEffect.h" | 23 #include "gl/GrGLEffect.h" |
| 24 #include "gl/GrGLSL.h" | 24 #include "gl/GrGLSL.h" |
| 25 | 25 |
| 26 namespace { | 26 namespace { |
| 27 // quadratics are rendered as 5-sided polys in order to bound the | 27 // quadratics are rendered as 5-sided polys in order to bound the |
| 28 // AA stroke around the center-curve. See comments in push_quad_index_buffer and | 28 // AA stroke around the center-curve. See comments in push_quad_index_buffer and |
| 29 // bloat_quad. | 29 // bloat_quad. |
| 30 static const int kVertsPerQuad = 5; | 30 static const int kVertsPerQuad = 5; |
| 31 static const int kIdxsPerQuad = 9; | 31 static const int kIdxsPerQuad = 9; |
| 32 | 32 |
| 33 static const int kVertsPerConic = 5; | |
| 34 static const int kIdxsPerConic = 9; | |
| 35 | |
| 33 static const int kVertsPerLineSeg = 4; | 36 static const int kVertsPerLineSeg = 4; |
| 34 static const int kIdxsPerLineSeg = 6; | 37 static const int kIdxsPerLineSeg = 6; |
| 35 | 38 |
| 36 static const int kNumQuadsInIdxBuffer = 256; | 39 static const int kNumQuadsInIdxBuffer = 256; |
| 37 static const size_t kQuadIdxSBufize = kIdxsPerQuad * | 40 static const size_t kQuadIdxSBufize = kIdxsPerQuad * |
| 38 sizeof(uint16_t) * | 41 sizeof(uint16_t) * |
| 39 kNumQuadsInIdxBuffer; | 42 kNumQuadsInIdxBuffer; |
| 43 static const int kNumConicsInIdxBuffer = 256; | |
| 44 static const size_t kConicIdxSBufize = kIdxsPerConic * | |
| 45 sizeof(uint16_t) * | |
| 46 kNumConicsInIdxBuffer; | |
| 40 | 47 |
| 41 bool push_quad_index_data(GrIndexBuffer* qIdxBuffer) { | 48 bool push_quad_index_data(GrIndexBuffer* qIdxBuffer) { |
| 42 uint16_t* data = (uint16_t*) qIdxBuffer->lock(); | 49 uint16_t* data = (uint16_t*) qIdxBuffer->lock(); |
| 43 bool tempData = NULL == data; | 50 bool tempData = NULL == data; |
| 44 if (tempData) { | 51 if (tempData) { |
| 45 data = SkNEW_ARRAY(uint16_t, kNumQuadsInIdxBuffer * kIdxsPerQuad); | 52 data = SkNEW_ARRAY(uint16_t, kNumQuadsInIdxBuffer * kIdxsPerQuad); |
| 46 } | 53 } |
| 47 for (int i = 0; i < kNumQuadsInIdxBuffer; ++i) { | 54 for (int i = 0; i < kNumQuadsInIdxBuffer; ++i) { |
| 48 | 55 |
| 49 // Each quadratic is rendered as a five sided polygon. This poly bounds | 56 // Each quadratic is rendered as a five sided polygon. This poly bounds |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 86 if (NULL == lIdxBuffer) { | 93 if (NULL == lIdxBuffer) { |
| 87 return NULL; | 94 return NULL; |
| 88 } | 95 } |
| 89 GrGpu* gpu = context->getGpu(); | 96 GrGpu* gpu = context->getGpu(); |
| 90 GrIndexBuffer* qIdxBuf = gpu->createIndexBuffer(kQuadIdxSBufize, false); | 97 GrIndexBuffer* qIdxBuf = gpu->createIndexBuffer(kQuadIdxSBufize, false); |
| 91 SkAutoTUnref<GrIndexBuffer> qIdxBuffer(qIdxBuf); | 98 SkAutoTUnref<GrIndexBuffer> qIdxBuffer(qIdxBuf); |
| 92 if (NULL == qIdxBuf || | 99 if (NULL == qIdxBuf || |
| 93 !push_quad_index_data(qIdxBuf)) { | 100 !push_quad_index_data(qIdxBuf)) { |
| 94 return NULL; | 101 return NULL; |
| 95 } | 102 } |
| 103 GrIndexBuffer* cIdxBuf = gpu->createIndexBuffer(kConicIdxSBufize, false); | |
| 104 if (NULL == cIdxBuf || | |
| 105 !push_quad_index_data(cIdxBuf)) { | |
|
bsalomon
2013/07/10 15:14:36
can't we just use one idx buffer then?
egdaniel
2013/07/10 20:34:18
I'm assuming you mean for the quad and conic corre
| |
| 106 return NULL; | |
| 107 } | |
| 96 return SkNEW_ARGS(GrAAHairLinePathRenderer, | 108 return SkNEW_ARGS(GrAAHairLinePathRenderer, |
| 97 (context, lIdxBuffer, qIdxBuf)); | 109 (context, lIdxBuffer, qIdxBuf, cIdxBuf)); |
| 98 } | 110 } |
| 99 | 111 |
| 100 GrAAHairLinePathRenderer::GrAAHairLinePathRenderer( | 112 GrAAHairLinePathRenderer::GrAAHairLinePathRenderer( |
| 101 const GrContext* context, | 113 const GrContext* context, |
| 102 const GrIndexBuffer* linesIndexBuffer, | 114 const GrIndexBuffer* linesIndexBuffer, |
| 103 const GrIndexBuffer* quadsIndexBuffer) { | 115 const GrIndexBuffer* quadsIndexBuffer, |
| 116 const GrIndexBuffer* conicIndexBuffer) { | |
| 104 fLinesIndexBuffer = linesIndexBuffer; | 117 fLinesIndexBuffer = linesIndexBuffer; |
| 105 linesIndexBuffer->ref(); | 118 linesIndexBuffer->ref(); |
| 106 fQuadsIndexBuffer = quadsIndexBuffer; | 119 fQuadsIndexBuffer = quadsIndexBuffer; |
| 107 quadsIndexBuffer->ref(); | 120 quadsIndexBuffer->ref(); |
| 121 fConicsIndexBuffer = conicIndexBuffer; | |
| 122 conicIndexBuffer->ref(); | |
| 108 } | 123 } |
| 109 | 124 |
| 110 GrAAHairLinePathRenderer::~GrAAHairLinePathRenderer() { | 125 GrAAHairLinePathRenderer::~GrAAHairLinePathRenderer() { |
| 111 fLinesIndexBuffer->unref(); | 126 fLinesIndexBuffer->unref(); |
| 112 fQuadsIndexBuffer->unref(); | 127 fQuadsIndexBuffer->unref(); |
| 128 fConicsIndexBuffer->unref(); | |
| 113 } | 129 } |
| 114 | 130 |
| 115 namespace { | 131 namespace { |
| 116 | 132 |
| 117 typedef SkTArray<SkPoint, true> PtArray; | 133 typedef SkTArray<SkPoint, true> PtArray; |
| 118 #define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true> | 134 #define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true> |
| 119 typedef SkTArray<int, true> IntArray; | 135 typedef SkTArray<int, true> IntArray; |
| 136 typedef SkTArray<float, true> FloatArray; | |
| 120 | 137 |
| 121 // Takes 178th time of logf on Z600 / VC2010 | 138 // Takes 178th time of logf on Z600 / VC2010 |
| 122 int get_float_exp(float x) { | 139 int get_float_exp(float x) { |
| 123 GR_STATIC_ASSERT(sizeof(int) == sizeof(float)); | 140 GR_STATIC_ASSERT(sizeof(int) == sizeof(float)); |
| 124 #if GR_DEBUG | 141 #if GR_DEBUG |
| 125 static bool tested; | 142 static bool tested; |
| 126 if (!tested) { | 143 if (!tested) { |
| 127 tested = true; | 144 tested = true; |
| 128 GrAssert(get_float_exp(0.25f) == -2); | 145 GrAssert(get_float_exp(0.25f) == -2); |
| 129 GrAssert(get_float_exp(0.3f) == -2); | 146 GrAssert(get_float_exp(0.3f) == -2); |
| 130 GrAssert(get_float_exp(0.5f) == -1); | 147 GrAssert(get_float_exp(0.5f) == -1); |
| 131 GrAssert(get_float_exp(1.f) == 0); | 148 GrAssert(get_float_exp(1.f) == 0); |
| 132 GrAssert(get_float_exp(2.f) == 1); | 149 GrAssert(get_float_exp(2.f) == 1); |
| 133 GrAssert(get_float_exp(2.5f) == 1); | 150 GrAssert(get_float_exp(2.5f) == 1); |
| 134 GrAssert(get_float_exp(8.f) == 3); | 151 GrAssert(get_float_exp(8.f) == 3); |
| 135 GrAssert(get_float_exp(100.f) == 6); | 152 GrAssert(get_float_exp(100.f) == 6); |
| 136 GrAssert(get_float_exp(1000.f) == 9); | 153 GrAssert(get_float_exp(1000.f) == 9); |
| 137 GrAssert(get_float_exp(1024.f) == 10); | 154 GrAssert(get_float_exp(1024.f) == 10); |
| 138 GrAssert(get_float_exp(3000000.f) == 21); | 155 GrAssert(get_float_exp(3000000.f) == 21); |
| 139 } | 156 } |
| 140 #endif | 157 #endif |
| 141 const int* iptr = (const int*)&x; | 158 const int* iptr = (const int*)&x; |
| 142 return (((*iptr) & 0x7f800000) >> 23) - 127; | 159 return (((*iptr) & 0x7f800000) >> 23) - 127; |
| 143 } | 160 } |
| 144 | 161 |
| 162 | |
| 163 // returns 0 if quad/conic is degen or close to it | |
| 164 // in this case approx the path with lines | |
| 165 // otherwise returns 1 | |
| 166 int is_degen_quad_conic(const SkPoint p[3]) { | |
|
bsalomon
2013/07/10 15:14:36
quad_or_conic?
| |
| 167 | |
| 168 static const SkScalar gDegenerateToLineTol = SK_Scalar1; | |
| 169 static const SkScalar gDegenerateToLineTolSqd = | |
| 170 SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol); | |
| 171 | |
| 172 if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd || | |
| 173 p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) { | |
| 174 return 1; | |
| 175 } | |
| 176 | |
| 177 SkScalar dsqd = p[1].distanceToLineBetweenSqd(p[0], p[2]); | |
| 178 if (dsqd < gDegenerateToLineTolSqd) { | |
| 179 return 1; | |
| 180 } | |
| 181 | |
| 182 if (p[2].distanceToLineBetweenSqd(p[1], p[0]) < gDegenerateToLineTolSqd) { | |
| 183 return 1; | |
| 184 } | |
| 185 return 0; | |
| 186 } | |
| 187 | |
| 145 // we subdivide the quads to avoid huge overfill | 188 // we subdivide the quads to avoid huge overfill |
| 146 // if it returns -1 then should be drawn as lines | 189 // if it returns -1 then should be drawn as lines |
| 147 int num_quad_subdivs(const SkPoint p[3]) { | 190 int num_quad_subdivs(const SkPoint p[3]) { |
| 148 static const SkScalar gDegenerateToLineTol = SK_Scalar1; | 191 static const SkScalar gDegenerateToLineTol = SK_Scalar1; |
| 149 static const SkScalar gDegenerateToLineTolSqd = | 192 static const SkScalar gDegenerateToLineTolSqd = |
| 150 SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol); | 193 SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol); |
| 151 | 194 |
| 152 if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd || | 195 if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd || |
| 153 p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) { | 196 p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) { |
| 154 return -1; | 197 return -1; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 200 * Quads are recorded in device space unless m contains | 243 * Quads are recorded in device space unless m contains |
| 201 * perspective, then in they are in src space. We do this because we will | 244 * perspective, then in they are in src space. We do this because we will |
| 202 * subdivide large quads to reduce over-fill. This subdivision has to be | 245 * subdivide large quads to reduce over-fill. This subdivision has to be |
| 203 * performed before applying the perspective matrix. | 246 * performed before applying the perspective matrix. |
| 204 */ | 247 */ |
| 205 int generate_lines_and_quads(const SkPath& path, | 248 int generate_lines_and_quads(const SkPath& path, |
| 206 const SkMatrix& m, | 249 const SkMatrix& m, |
| 207 const GrIRect& devClipBounds, | 250 const GrIRect& devClipBounds, |
| 208 PtArray* lines, | 251 PtArray* lines, |
| 209 PtArray* quads, | 252 PtArray* quads, |
| 210 IntArray* quadSubdivCnts) { | 253 PtArray* conics, |
| 254 IntArray* quadSubdivCnts, | |
| 255 FloatArray* conicWeights) { | |
| 211 SkPath::Iter iter(path, false); | 256 SkPath::Iter iter(path, false); |
| 212 | 257 |
| 213 int totalQuadCount = 0; | 258 int totalQuadCount = 0; |
| 214 GrRect bounds; | 259 GrRect bounds; |
| 215 GrIRect ibounds; | 260 GrIRect ibounds; |
| 216 | 261 |
| 217 bool persp = m.hasPerspective(); | 262 bool persp = m.hasPerspective(); |
| 218 | 263 |
| 219 for (;;) { | 264 for (;;) { |
| 220 GrPoint pathPts[4]; | 265 GrPoint pathPts[4]; |
| 221 GrPoint devPts[4]; | 266 GrPoint devPts[4]; |
| 222 SkPath::Verb verb = iter.next(pathPts); | 267 SkPath::Verb verb = iter.next(pathPts); |
| 223 switch (verb) { | 268 switch (verb) { |
| 224 case SkPath::kConic_Verb: | 269 case SkPath::kConic_Verb: { |
| 225 SkASSERT(0); | 270 SkScalar t = SkGetTQuadAtMaxCurvature(pathPts); |
|
bsalomon
2013/07/10 15:14:36
maybe this whole bit up to the for should be added
| |
| 271 int conicCnt = 1; | |
| 272 SkConic dst[2]; | |
| 273 if (t == 0) | |
| 274 { | |
|
bsalomon
2013/07/10 15:14:36
move {s up to prev line
| |
| 275 dst[0].set(pathPts, iter.conicWeight()); | |
| 276 } | |
| 277 else | |
| 278 { | |
| 279 SkConic conic; | |
| 280 conic.set(pathPts, iter.conicWeight()); | |
| 281 conic.chopAt(t, dst); | |
| 282 conicCnt = 2; | |
| 283 } | |
| 284 for (int i = 0; i < conicCnt; ++i) { | |
| 285 SkPoint* chopPnts = dst[i].fPts; | |
| 286 m.mapPoints(devPts, chopPnts, 3); | |
| 287 bounds.setBounds(devPts, 3); | |
| 288 bounds.outset(SK_Scalar1, SK_Scalar1); | |
| 289 bounds.roundOut(&ibounds); | |
| 290 if (SkIRect::Intersects(devClipBounds, ibounds)) { | |
| 291 if (is_degen_quad_conic(devPts)) { | |
| 292 SkPoint* pts = lines->push_back_n(4); | |
| 293 pts[0] = devPts[0]; | |
| 294 pts[1] = devPts[1]; | |
| 295 pts[2] = devPts[1]; | |
| 296 pts[3] = devPts[2]; | |
| 297 } else { | |
| 298 // when in perspective keep conics in src space ??? | |
|
bsalomon
2013/07/10 15:14:36
should test this... but yes. The later chopping th
| |
| 299 SkPoint* cPts = persp ? chopPnts : devPts; | |
| 300 SkPoint* pts = conics->push_back_n(3); | |
| 301 pts[0] = cPts[0]; | |
| 302 pts[1] = cPts[1]; | |
| 303 pts[2] = cPts[2]; | |
| 304 conicWeights->push_back() = dst[i].fW; | |
| 305 } | |
| 306 } | |
| 307 } | |
| 308 } | |
| 226 break; | 309 break; |
| 227 case SkPath::kMove_Verb: | 310 case SkPath::kMove_Verb: |
| 228 break; | 311 break; |
| 229 case SkPath::kLine_Verb: | 312 case SkPath::kLine_Verb: |
| 230 m.mapPoints(devPts, pathPts, 2); | 313 m.mapPoints(devPts, pathPts, 2); |
| 231 bounds.setBounds(devPts, 2); | 314 bounds.setBounds(devPts, 2); |
| 232 bounds.outset(SK_Scalar1, SK_Scalar1); | 315 bounds.outset(SK_Scalar1, SK_Scalar1); |
| 233 bounds.roundOut(&ibounds); | 316 bounds.roundOut(&ibounds); |
| 234 if (SkIRect::Intersects(devClipBounds, ibounds)) { | 317 if (SkIRect::Intersects(devClipBounds, ibounds)) { |
| 235 SkPoint* pts = lines->push_back_n(2); | 318 SkPoint* pts = lines->push_back_n(2); |
| 236 pts[0] = devPts[0]; | 319 pts[0] = devPts[0]; |
| 237 pts[1] = devPts[1]; | 320 pts[1] = devPts[1]; |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 341 } | 424 } |
| 342 | 425 |
| 343 struct Vertex { | 426 struct Vertex { |
| 344 GrPoint fPos; | 427 GrPoint fPos; |
| 345 union { | 428 union { |
| 346 struct { | 429 struct { |
| 347 SkScalar fA; | 430 SkScalar fA; |
| 348 SkScalar fB; | 431 SkScalar fB; |
| 349 SkScalar fC; | 432 SkScalar fC; |
| 350 } fLine; | 433 } fLine; |
| 434 struct { | |
| 435 SkScalar fA; | |
| 436 SkScalar fB; | |
| 437 SkScalar fC; | |
| 438 SkScalar fD; | |
| 439 SkScalar fE; | |
| 440 SkScalar fF; | |
| 441 } fConic; | |
| 351 GrVec fQuadCoord; | 442 GrVec fQuadCoord; |
| 352 struct { | 443 struct { |
| 353 SkScalar fBogus[4]; | 444 SkScalar fBogus[6]; |
| 354 }; | 445 }; |
| 355 }; | 446 }; |
| 356 }; | 447 }; |
| 357 GR_STATIC_ASSERT(sizeof(Vertex) == 3 * sizeof(GrPoint)); | 448 |
| 449 GR_STATIC_ASSERT(sizeof(Vertex) == 4 * sizeof(GrPoint)); | |
| 358 | 450 |
| 359 void intersect_lines(const SkPoint& ptA, const SkVector& normA, | 451 void intersect_lines(const SkPoint& ptA, const SkVector& normA, |
| 360 const SkPoint& ptB, const SkVector& normB, | 452 const SkPoint& ptB, const SkVector& normB, |
| 361 SkPoint* result) { | 453 SkPoint* result) { |
| 362 | 454 |
| 363 SkScalar lineAW = -normA.dot(ptA); | 455 SkScalar lineAW = -normA.dot(ptA); |
| 364 SkScalar lineBW = -normB.dot(ptB); | 456 SkScalar lineBW = -normB.dot(ptB); |
| 365 | 457 |
| 366 SkScalar wInv = SkScalarMul(normA.fX, normB.fY) - | 458 SkScalar wInv = SkScalarMul(normA.fX, normB.fY) - |
| 367 SkScalarMul(normA.fY, normB.fX); | 459 SkScalarMul(normA.fY, normB.fX); |
| 368 wInv = SkScalarInvert(wInv); | 460 wInv = SkScalarInvert(wInv); |
| 369 | 461 |
| 370 result->fX = SkScalarMul(normA.fY, lineBW) - SkScalarMul(lineAW, normB.fY); | 462 result->fX = SkScalarMul(normA.fY, lineBW) - SkScalarMul(lineAW, normB.fY); |
| 371 result->fX = SkScalarMul(result->fX, wInv); | 463 result->fX = SkScalarMul(result->fX, wInv); |
| 372 | 464 |
| 373 result->fY = SkScalarMul(lineAW, normB.fX) - SkScalarMul(normA.fX, lineBW); | 465 result->fY = SkScalarMul(lineAW, normB.fX) - SkScalarMul(normA.fX, lineBW); |
| 374 result->fY = SkScalarMul(result->fY, wInv); | 466 result->fY = SkScalarMul(result->fY, wInv); |
| 375 } | 467 } |
| 376 | 468 |
| 377 void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, | 469 void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 447 // include it. | 539 // include it. |
| 448 intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos); | 540 intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos); |
| 449 devBounds->growToInclude(b0.fPos.fX, b0.fPos.fY); | 541 devBounds->growToInclude(b0.fPos.fX, b0.fPos.fY); |
| 450 | 542 |
| 451 if (toSrc) { | 543 if (toSrc) { |
| 452 toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(Vertex), kVertsPerQuad ); | 544 toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(Vertex), kVertsPerQuad ); |
| 453 } | 545 } |
| 454 DevToUV.apply<kVertsPerQuad, sizeof(Vertex), sizeof(GrPoint)>(verts); | 546 DevToUV.apply<kVertsPerQuad, sizeof(Vertex), sizeof(GrPoint)>(verts); |
| 455 } | 547 } |
| 456 | 548 |
| 549 | |
| 550 // Input Parametric: | |
| 551 // P(t) = (P0*(1-t)^2 + 2*w*P1*t*(1-t) + P2*t^2) / (1-t)^2 + 2*w*t*(1-t) + t^2) | |
| 552 // Output Implicit: | |
| 553 // Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0 | |
| 554 // A = 4w^2*(y0-y1)(y1-y2)-(y0-y2)^2 | |
| 555 // B = 4w^2*((x0-x1)(y2-y1)+(x1-x2)(y1-y0)) + 2(x0-x2)(y0-y2) | |
| 556 // C = 4w^2(x0-x1)(x1-x2) - (x0-x2)^2 | |
| 557 // D = 4w^2((x0y1-x1y0)(y1-y2)+(x1y2-x2y1)(y0-y1)) + 2(y2-y0)(x0y2-x2y0) | |
| 558 // E = 4w^2((y0x1-y1x0)(x1-x2)+(y1x2-y2x1)(x0-x1)) + 2(x2-x0)(y0x2-y2x0) | |
| 559 // F = 4w^2(x1y2-x2y1)(x0y1-x1y0) - (x2y0-x0y2)^2 | |
| 560 | |
| 561 void set_conic_coeffs(const SkPoint p[3], Vertex verts[kVertsPerConic], const fl oat weight) { | |
| 562 const float ww4 = 4 * weight * weight; | |
| 563 const float x0Mx1 = p[0].fX - p[1].fX; | |
| 564 const float x1Mx2 = p[1].fX - p[2].fX; | |
| 565 const float x0Mx2 = p[0].fX - p[2].fX; | |
| 566 const float y0My1 = p[0].fY - p[1].fY; | |
| 567 const float y1My2 = p[1].fY - p[2].fY; | |
| 568 const float y0My2 = p[0].fY - p[2].fY; | |
| 569 const float x0y1Mx1y0 = p[0].fX*p[1].fY - p[1].fX*p[0].fY; | |
| 570 const float x1y2Mx2y1 = p[1].fX*p[2].fY - p[2].fX*p[1].fY; | |
| 571 const float x0y2Mx2y0 = p[0].fX*p[2].fY - p[2].fX*p[0].fY; | |
| 572 const float a = ww4 * y0My1 * y1My2 - y0My2 * y0My2; | |
| 573 const float b = -ww4 * (x0Mx1 * y1My2 + x1Mx2 * y0My1) + 2 * x0Mx2 * y0My2; | |
| 574 const float c = ww4 * x0Mx1 * x1Mx2 - x0Mx2 * x0Mx2; | |
| 575 const float d = ww4 * (x0y1Mx1y0 * y1My2 + x1y2Mx2y1 * y0My1) - 2 * y0My2 * x0y2Mx2y0; | |
| 576 const float e = -ww4 * (x0y1Mx1y0 * x1Mx2 + x1y2Mx2y1 * x0Mx1) + 2 * x0Mx2 * x0y2Mx2y0; | |
| 577 const float f = ww4 * x1y2Mx2y1 * x0y1Mx1y0 - x0y2Mx2y0 * x0y2Mx2y0; | |
| 578 | |
| 579 for (int i = 0; i < kVertsPerConic; ++i) { | |
| 580 verts[i].fConic.fA = a/f; | |
| 581 verts[i].fConic.fB = b/f; | |
| 582 verts[i].fConic.fC = c/f; | |
| 583 verts[i].fConic.fD = d/f; | |
| 584 verts[i].fConic.fE = e/f; | |
| 585 verts[i].fConic.fF = f/f; | |
| 586 } | |
| 587 } | |
| 588 | |
| 589 void add_conics(const SkPoint p[3], | |
| 590 float weight, | |
| 591 const SkMatrix* toDevice, | |
| 592 const SkMatrix* toSrc, | |
| 593 Vertex** vert, | |
| 594 SkRect* devBounds) { | |
| 595 bloat_quad(p, toDevice, toSrc, *vert, devBounds); | |
| 596 set_conic_coeffs(p, *vert, weight); | |
| 597 *vert += kVertsPerConic; | |
| 598 } | |
| 599 | |
| 457 void add_quads(const SkPoint p[3], | 600 void add_quads(const SkPoint p[3], |
| 458 int subdiv, | 601 int subdiv, |
| 459 const SkMatrix* toDevice, | 602 const SkMatrix* toDevice, |
| 460 const SkMatrix* toSrc, | 603 const SkMatrix* toSrc, |
| 461 Vertex** vert, | 604 Vertex** vert, |
| 462 SkRect* devBounds) { | 605 SkRect* devBounds) { |
| 463 GrAssert(subdiv >= 0); | 606 GrAssert(subdiv >= 0); |
| 464 if (subdiv) { | 607 if (subdiv) { |
| 465 SkPoint newP[5]; | 608 SkPoint newP[5]; |
| 466 SkChopQuadAtHalf(p, newP); | 609 SkChopQuadAtHalf(p, newP); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 508 (*vert)[1].fPos.set(SK_ScalarMax, SK_ScalarMax); | 651 (*vert)[1].fPos.set(SK_ScalarMax, SK_ScalarMax); |
| 509 (*vert)[2].fPos.set(SK_ScalarMax, SK_ScalarMax); | 652 (*vert)[2].fPos.set(SK_ScalarMax, SK_ScalarMax); |
| 510 (*vert)[3].fPos.set(SK_ScalarMax, SK_ScalarMax); | 653 (*vert)[3].fPos.set(SK_ScalarMax, SK_ScalarMax); |
| 511 } | 654 } |
| 512 | 655 |
| 513 *vert += kVertsPerLineSeg; | 656 *vert += kVertsPerLineSeg; |
| 514 } | 657 } |
| 515 | 658 |
| 516 } | 659 } |
| 517 | 660 |
| 661 /** | |
| 662 * The output of this effect is a hairline edge for conics. | |
| 663 * Conics specified by implicit equation Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0. | |
| 664 * A, B, C, D are the first vec4 of vertex attributes and | |
| 665 * E and F are the vec2 attached to 2nd vertex attrribute. | |
| 666 * Coverage is max(0, 1-distance). | |
| 667 */ | |
| 668 class HairConicEdgeEffect : public GrEffect { | |
| 669 public: | |
| 670 | |
| 671 static GrEffectRef* Create() { | |
| 672 GR_CREATE_STATIC_EFFECT(gHairConicEdgeEffect, HairConicEdgeEffect, ()); | |
| 673 gHairConicEdgeEffect->ref(); | |
| 674 return gHairConicEdgeEffect; | |
| 675 } | |
| 676 | |
| 677 virtual ~HairConicEdgeEffect() {} | |
| 678 | |
| 679 static const char* Name() { return "HairConicEdge"; } | |
| 680 | |
| 681 virtual void getConstantColorComponents(GrColor* color, | |
| 682 uint32_t* validFlags) const SK_OVERR IDE { | |
| 683 *validFlags = 0; | |
| 684 } | |
| 685 | |
| 686 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { | |
| 687 return GrTBackendEffectFactory<HairConicEdgeEffect>::getInstance(); | |
| 688 } | |
| 689 | |
| 690 class GLEffect : public GrGLEffect { | |
| 691 public: | |
| 692 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) | |
| 693 : INHERITED (factory) {} | |
| 694 | |
| 695 virtual void emitCode(GrGLShaderBuilder* builder, | |
| 696 const GrDrawEffect& drawEffect, | |
| 697 EffectKey key, | |
| 698 const char* outputColor, | |
| 699 const char* inputColor, | |
| 700 const TextureSamplerArray& samplers) SK_OVERRIDE { | |
| 701 const char *vsCoeffABCDName, *fsCoeffABCDName; | |
| 702 const char *vsCoeffEFName, *fsCoeffEFName; | |
| 703 | |
| 704 SkAssertResult(builder->enableFeature( | |
| 705 GrGLShaderBuilder::kStandardDerivatives_GLSLFeature)); | |
| 706 builder->addVarying(kVec4f_GrSLType, "ConicCoeffsABCD", | |
| 707 &vsCoeffABCDName, &fsCoeffABCDName); | |
| 708 const SkString* attr0Name = | |
| 709 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[0]); | |
| 710 builder->vsCodeAppendf("\t%s = %s;\n", vsCoeffABCDName, attr0Name->c _str()); | |
| 711 | |
| 712 builder->addVarying(kVec2f_GrSLType, "ConicCoeffsEF", | |
| 713 &vsCoeffEFName, &fsCoeffEFName); | |
| 714 const SkString* attr1Name = | |
| 715 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[1]); | |
| 716 builder->vsCodeAppendf("\t%s = %s;\n", vsCoeffEFName, attr1Name->c_s tr()); | |
| 717 | |
| 718 // Based on Gustavson 2006: "Beyond the Pixel: towards infinite reso lution textures" | |
| 719 builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n"); | |
| 720 | |
| 721 builder->fsCodeAppendf("\t\tvec3 uv1 = vec3(%s.xy, 1);\n", builder-> fragmentPosition()); | |
| 722 builder->fsCodeAppend("\t\tvec3 u2uvv2 = uv1.xxy * uv1.xyy;\n"); | |
| 723 builder->fsCodeAppendf("\t\tvec3 ABC = %s.xyz;\n", fsCoeffABCDName); | |
| 724 builder->fsCodeAppendf("\t\tvec3 DEF = vec3(%s.w, %s.xy);\n", | |
| 725 fsCoeffABCDName, fsCoeffEFName); | |
| 726 | |
| 727 builder->fsCodeAppend("\t\tfloat dfdx = dot(uv1,vec3(2.0*ABC.x,ABC.y ,DEF.x));\n"); | |
| 728 builder->fsCodeAppend("\t\tfloat dfdy = dot(uv1,vec3(ABC.y, 2.0*ABC. z,DEF.y));\n"); | |
| 729 builder->fsCodeAppend("\t\tfloat gF = dfdx*dfdx + dfdy*dfdy;\n"); | |
| 730 builder->fsCodeAppend("\t\tedgeAlpha = dot(ABC,u2uvv2) + dot(DEF,uv1 );\n"); | |
| 731 builder->fsCodeAppend("\t\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / gF );\n"); | |
| 732 builder->fsCodeAppend("\t\tedgeAlpha = max((1.0 - edgeAlpha), 0.0);\ n"); | |
| 733 // Add line below for smooth cubic ramp | |
| 734 // builder->fsCodeAppend("\t\tedgeAlpha = edgeAlpha*edgeAlpha*(3.0-2 .0*edgeAlpha);\n"); | |
| 735 | |
| 736 SkString modulate; | |
| 737 GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha"); | |
| 738 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str() ); | |
| 739 | |
| 740 } | |
| 741 | |
| 742 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrG LCaps&) { | |
| 743 return 0x0; | |
| 744 } | |
| 745 | |
| 746 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_ OVERRIDE {} | |
| 747 | |
| 748 private: | |
| 749 typedef GrGLEffect INHERITED; | |
| 750 }; | |
| 751 | |
| 752 private: | |
| 753 HairConicEdgeEffect() { | |
| 754 this->addVertexAttrib(kVec4f_GrSLType); | |
| 755 this->addVertexAttrib(kVec2f_GrSLType); | |
| 756 this->setWillReadFragmentPosition(); | |
| 757 } | |
| 758 | |
| 759 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE { | |
| 760 return true; | |
| 761 } | |
| 762 | |
| 763 GR_DECLARE_EFFECT_TEST; | |
| 764 | |
| 765 typedef GrEffect INHERITED; | |
| 766 }; | |
| 767 | |
| 768 GR_DEFINE_EFFECT_TEST(HairConicEdgeEffect); | |
| 769 | |
| 770 GrEffectRef* HairConicEdgeEffect::TestCreate(SkMWCRandom* random, | |
| 771 GrContext*, | |
| 772 const GrDrawTargetCaps& caps, | |
| 773 GrTexture*[]) { | |
| 774 return HairConicEdgeEffect::Create(); | |
| 775 } | |
| 518 /////////////////////////////////////////////////////////////////////////////// | 776 /////////////////////////////////////////////////////////////////////////////// |
| 519 | 777 |
| 520 /** | 778 /** |
| 521 * The output of this effect is a hairline edge for quadratics. | 779 * The output of this effect is a hairline edge for quadratics. |
| 522 * Quadratic specified by 0=u^2-v canonical coords. u and v are the first | 780 * Quadratic specified by 0=u^2-v canonical coords. u and v are the first |
| 523 * two components of the vertex attribute. Uses unsigned distance. | 781 * two components of the vertex attribute. Uses unsigned distance. |
| 524 * Coverage is min(0, 1-distance). 3rd & 4th component unused. | 782 * Coverage is min(0, 1-distance). 3rd & 4th component unused. |
| 525 * Requires shader derivative instruction support. | 783 * Requires shader derivative instruction support. |
| 526 */ | 784 */ |
| 527 class HairQuadEdgeEffect : public GrEffect { | 785 class HairQuadEdgeEffect : public GrEffect { |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 556 EffectKey key, | 814 EffectKey key, |
| 557 const char* outputColor, | 815 const char* outputColor, |
| 558 const char* inputColor, | 816 const char* inputColor, |
| 559 const TextureSamplerArray& samplers) SK_OVERRIDE { | 817 const TextureSamplerArray& samplers) SK_OVERRIDE { |
| 560 const char *vsName, *fsName; | 818 const char *vsName, *fsName; |
| 561 const SkString* attrName = | 819 const SkString* attrName = |
| 562 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[0]); | 820 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[0]); |
| 563 builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n"); | 821 builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n"); |
| 564 | 822 |
| 565 SkAssertResult(builder->enableFeature( | 823 SkAssertResult(builder->enableFeature( |
| 566 GrGLShaderBuilder::kStandardDeriva tives_GLSLFeature)); | 824 GrGLShaderBuilder::kStandardDerivatives_GLSLFeature)); |
| 567 builder->addVarying(kVec4f_GrSLType, "HairQuadEdge", &vsName, &fsNam e); | 825 builder->addVarying(kVec4f_GrSLType, "HairQuadEdge", &vsName, &fsNam e); |
| 568 | 826 |
| 569 builder->fsCodeAppendf("\t\tvec2 duvdx = dFdx(%s.xy);\n", fsName); | 827 builder->fsCodeAppendf("\t\tvec2 duvdx = dFdx(%s.xy);\n", fsName); |
| 570 builder->fsCodeAppendf("\t\tvec2 duvdy = dFdy(%s.xy);\n", fsName); | 828 builder->fsCodeAppendf("\t\tvec2 duvdy = dFdy(%s.xy);\n", fsName); |
| 571 builder->fsCodeAppendf("\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx. y,\n" | 829 builder->fsCodeAppendf("\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx. y,\n" |
| 572 "\t\t 2.0*%s.x*duvdy.x - duvdy. y);\n", | 830 "\t\t 2.0*%s.x*duvdy.x - duvdy. y);\n", |
| 573 fsName, fsName); | 831 fsName, fsName); |
| 574 builder->fsCodeAppendf("\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsNa me, fsName, | 832 builder->fsCodeAppendf("\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsNa me, fsName, |
| 575 fsName); | 833 fsName); |
| 576 builder->fsCodeAppend("\t\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / do t(gF, gF));\n"); | 834 builder->fsCodeAppend("\t\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / do t(gF, gF));\n"); |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 607 typedef GrEffect INHERITED; | 865 typedef GrEffect INHERITED; |
| 608 }; | 866 }; |
| 609 | 867 |
| 610 GR_DEFINE_EFFECT_TEST(HairQuadEdgeEffect); | 868 GR_DEFINE_EFFECT_TEST(HairQuadEdgeEffect); |
| 611 | 869 |
| 612 GrEffectRef* HairQuadEdgeEffect::TestCreate(SkMWCRandom* random, | 870 GrEffectRef* HairQuadEdgeEffect::TestCreate(SkMWCRandom* random, |
| 613 GrContext*, | 871 GrContext*, |
| 614 const GrDrawTargetCaps& caps, | 872 const GrDrawTargetCaps& caps, |
| 615 GrTexture*[]) { | 873 GrTexture*[]) { |
| 616 // Doesn't work without derivative instructions. | 874 // Doesn't work without derivative instructions. |
| 617 return caps.shaderDerivativeSupport() ? HairQuadEdgeEffect::Create() : NULL; } | 875 return caps.shaderDerivativeSupport() ? HairQuadEdgeEffect::Create() : NULL; |
| 876 } | |
| 618 | 877 |
| 619 /////////////////////////////////////////////////////////////////////////////// | 878 /////////////////////////////////////////////////////////////////////////////// |
| 620 | 879 |
| 621 /** | 880 /** |
| 622 * The output of this effect is a 1-pixel wide line. | 881 * The output of this effect is a 1-pixel wide line. |
| 623 * Input is 2D implicit device coord line eq (a*x + b*y +c = 0). 4th component u nused. | 882 * Input is 2D implicit device coord line eq (a*x + b*y +c = 0). 4th component u nused. |
| 624 */ | 883 */ |
| 625 class HairLineEdgeEffect : public GrEffect { | 884 class HairLineEdgeEffect : public GrEffect { |
| 626 public: | 885 public: |
| 627 | 886 |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 710 /////////////////////////////////////////////////////////////////////////////// | 969 /////////////////////////////////////////////////////////////////////////////// |
| 711 | 970 |
| 712 namespace { | 971 namespace { |
| 713 | 972 |
| 714 // position + edge | 973 // position + edge |
| 715 extern const GrVertexAttrib gHairlineAttribs[] = { | 974 extern const GrVertexAttrib gHairlineAttribs[] = { |
| 716 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBind ing}, | 975 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBind ing}, |
| 717 {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBindin g} | 976 {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBindin g} |
| 718 }; | 977 }; |
| 719 | 978 |
| 979 // Conic | |
| 980 // position + ABCD + EF | |
| 981 extern const GrVertexAttrib gConicVertexAttribs[] = { | |
| 982 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBind ing }, | |
| 983 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBindin g }, | |
| 984 { kVec2f_GrVertexAttribType, 3*sizeof(GrPoint), kEffect_GrVertexAttribBindin g } | |
| 985 }; | |
| 720 }; | 986 }; |
| 721 | 987 |
| 722 bool GrAAHairLinePathRenderer::createGeom( | 988 bool GrAAHairLinePathRenderer::createGeom( |
| 723 const SkPath& path, | 989 const SkPath& path, |
| 724 GrDrawTarget* target, | 990 GrDrawTarget* target, |
| 725 int* lineCnt, | 991 int* lineCnt, |
| 726 int* quadCnt, | 992 int* quadCnt, |
| 993 int* conicCnt, | |
| 727 GrDrawTarget::AutoReleaseGeometry* arg, | 994 GrDrawTarget::AutoReleaseGeometry* arg, |
| 728 SkRect* devBounds) { | 995 SkRect* devBounds) { |
| 729 GrDrawState* drawState = target->drawState(); | 996 GrDrawState* drawState = target->drawState(); |
| 730 int rtHeight = drawState->getRenderTarget()->height(); | 997 int rtHeight = drawState->getRenderTarget()->height(); |
| 731 | 998 |
| 732 GrIRect devClipBounds; | 999 GrIRect devClipBounds; |
| 733 target->getClip()->getConservativeBounds(drawState->getRenderTarget(), &devC lipBounds); | 1000 target->getClip()->getConservativeBounds(drawState->getRenderTarget(), &devC lipBounds); |
| 734 | 1001 |
| 735 SkMatrix viewM = drawState->getViewMatrix(); | 1002 SkMatrix viewM = drawState->getViewMatrix(); |
| 736 | 1003 |
| 737 // All the vertices that we compute are within 1 of path control points with the exception of | 1004 // All the vertices that we compute are within 1 of path control points with the exception of |
| 738 // one of the bounding vertices for each quad. The add_quads() function will update the bounds | 1005 // one of the bounding vertices for each quad. The add_quads() function will update the bounds |
| 739 // for each quad added. | 1006 // for each quad added. |
| 740 *devBounds = path.getBounds(); | 1007 *devBounds = path.getBounds(); |
| 741 viewM.mapRect(devBounds); | 1008 viewM.mapRect(devBounds); |
| 742 devBounds->outset(SK_Scalar1, SK_Scalar1); | 1009 devBounds->outset(SK_Scalar1, SK_Scalar1); |
| 743 | 1010 |
| 744 PREALLOC_PTARRAY(128) lines; | 1011 PREALLOC_PTARRAY(128) lines; |
| 745 PREALLOC_PTARRAY(128) quads; | 1012 PREALLOC_PTARRAY(128) quads; |
| 1013 PREALLOC_PTARRAY(128) conics; | |
| 746 IntArray qSubdivs; | 1014 IntArray qSubdivs; |
| 1015 FloatArray cWeights; | |
| 747 *quadCnt = generate_lines_and_quads(path, viewM, devClipBounds, | 1016 *quadCnt = generate_lines_and_quads(path, viewM, devClipBounds, |
| 748 &lines, &quads, &qSubdivs); | 1017 &lines, &quads, &conics, &qSubdivs, &cWe ights); |
| 749 | 1018 |
| 750 *lineCnt = lines.count() / 2; | 1019 *lineCnt = lines.count() / 2; |
| 751 int vertCnt = kVertsPerLineSeg * *lineCnt + kVertsPerQuad * *quadCnt; | 1020 *conicCnt = conics.count() / 3; |
| 1021 int vertCnt = kVertsPerLineSeg * *lineCnt + kVertsPerQuad * *quadCnt + | |
| 1022 kVertsPerConic * *conicCnt; | |
| 752 | 1023 |
| 753 target->drawState()->setVertexAttribs<gHairlineAttribs>(SK_ARRAY_COUNT(gHair lineAttribs)); | 1024 target->drawState()->setVertexAttribs<gConicVertexAttribs>(SK_ARRAY_COUNT(gC onicVertexAttribs)); |
| 754 GrAssert(sizeof(Vertex) == target->getDrawState().getVertexSize()); | 1025 GrAssert(sizeof(Vertex) == target->getDrawState().getVertexSize()); |
| 755 | 1026 |
| 756 if (!arg->set(target, vertCnt, 0)) { | 1027 if (!arg->set(target, vertCnt, 0)) { |
| 757 return false; | 1028 return false; |
| 758 } | 1029 } |
| 759 | 1030 |
| 760 Vertex* verts = reinterpret_cast<Vertex*>(arg->vertices()); | 1031 Vertex* verts = reinterpret_cast<Vertex*>(arg->vertices()); |
| 761 | 1032 |
| 762 const SkMatrix* toDevice = NULL; | 1033 const SkMatrix* toDevice = NULL; |
| 763 const SkMatrix* toSrc = NULL; | 1034 const SkMatrix* toSrc = NULL; |
| 764 SkMatrix ivm; | 1035 SkMatrix ivm; |
| 765 | 1036 |
| 766 if (viewM.hasPerspective()) { | 1037 if (viewM.hasPerspective()) { |
| 767 if (viewM.invert(&ivm)) { | 1038 if (viewM.invert(&ivm)) { |
| 768 toDevice = &viewM; | 1039 toDevice = &viewM; |
| 769 toSrc = &ivm; | 1040 toSrc = &ivm; |
| 770 } | 1041 } |
| 771 } | 1042 } |
| 772 | 1043 |
| 773 for (int i = 0; i < *lineCnt; ++i) { | 1044 for (int i = 0; i < *lineCnt; ++i) { |
| 774 add_line(&lines[2*i], rtHeight, toSrc, &verts); | 1045 add_line(&lines[2*i], rtHeight, toSrc, &verts); |
| 775 } | 1046 } |
| 776 | 1047 |
| 777 int unsubdivQuadCnt = quads.count() / 3; | 1048 int unsubdivQuadCnt = quads.count() / 3; |
| 778 for (int i = 0; i < unsubdivQuadCnt; ++i) { | 1049 for (int i = 0; i < unsubdivQuadCnt; ++i) { |
| 779 GrAssert(qSubdivs[i] >= 0); | 1050 GrAssert(qSubdivs[i] >= 0); |
| 780 add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts, devBounds); | 1051 add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts, devBounds); |
| 781 } | 1052 } |
| 782 | 1053 |
| 1054 // Start Conics | |
| 1055 for (int i = 0; i < *conicCnt; ++i) { | |
| 1056 add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &verts, devBounds ); | |
| 1057 } | |
| 783 return true; | 1058 return true; |
| 784 } | 1059 } |
| 785 | 1060 |
| 786 bool GrAAHairLinePathRenderer::canDrawPath(const SkPath& path, | 1061 bool GrAAHairLinePathRenderer::canDrawPath(const SkPath& path, |
| 787 const SkStrokeRec& stroke, | 1062 const SkStrokeRec& stroke, |
| 788 const GrDrawTarget* target, | 1063 const GrDrawTarget* target, |
| 789 bool antiAlias) const { | 1064 bool antiAlias) const { |
| 790 if (!stroke.isHairlineStyle() || !antiAlias) { | 1065 if (!stroke.isHairlineStyle() || !antiAlias) { |
| 791 return false; | 1066 return false; |
| 792 } | 1067 } |
| 793 | 1068 |
| 794 static const uint32_t gReqDerivMask = SkPath::kCubic_SegmentMask | | 1069 static const uint32_t gReqDerivMask = SkPath::kCubic_SegmentMask | |
| 795 SkPath::kQuad_SegmentMask; | 1070 SkPath::kQuad_SegmentMask; |
| 796 if (!target->caps()->shaderDerivativeSupport() && | 1071 if (!target->caps()->shaderDerivativeSupport() && |
| 797 (gReqDerivMask & path.getSegmentMasks())) { | 1072 (gReqDerivMask & path.getSegmentMasks())) { |
| 798 return false; | 1073 return false; |
| 799 } | 1074 } |
| 800 return true; | 1075 return true; |
| 801 } | 1076 } |
| 802 | 1077 |
| 803 bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path, | 1078 bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path, |
| 804 const SkStrokeRec&, | 1079 const SkStrokeRec&, |
| 805 GrDrawTarget* target, | 1080 GrDrawTarget* target, |
| 806 bool antiAlias) { | 1081 bool antiAlias) { |
| 807 | 1082 |
| 808 int lineCnt; | 1083 int lineCnt; |
| 809 int quadCnt; | 1084 int quadCnt; |
| 1085 int conicCnt; | |
| 810 GrDrawTarget::AutoReleaseGeometry arg; | 1086 GrDrawTarget::AutoReleaseGeometry arg; |
| 811 SkRect devBounds; | 1087 SkRect devBounds; |
| 812 | 1088 |
| 813 if (!this->createGeom(path, | 1089 if (!this->createGeom(path, |
| 814 target, | 1090 target, |
| 815 &lineCnt, | 1091 &lineCnt, |
| 816 &quadCnt, | 1092 &quadCnt, |
| 1093 &conicCnt, | |
| 817 &arg, | 1094 &arg, |
| 818 &devBounds)) { | 1095 &devBounds)) { |
| 819 return false; | 1096 return false; |
| 820 } | 1097 } |
| 821 | 1098 |
| 822 GrDrawTarget::AutoStateRestore asr; | 1099 GrDrawTarget::AutoStateRestore asr; |
| 823 | 1100 |
| 824 // createGeom transforms the geometry to device space when the matrix does n ot have | 1101 // createGeom transforms the geometry to device space when the matrix does n ot have |
| 825 // perspective. | 1102 // perspective. |
| 826 if (target->getDrawState().getViewMatrix().hasPerspective()) { | 1103 if (target->getDrawState().getViewMatrix().hasPerspective()) { |
| 827 asr.set(target, GrDrawTarget::kPreserve_ASRInit); | 1104 asr.set(target, GrDrawTarget::kPreserve_ASRInit); |
| 828 } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) { | 1105 } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) { |
| 829 return false; | 1106 return false; |
| 830 } | 1107 } |
| 831 GrDrawState* drawState = target->drawState(); | 1108 GrDrawState* drawState = target->drawState(); |
| 832 | 1109 |
| 833 // TODO: See whether rendering lines as degenerate quads improves perf | 1110 // TODO: See whether rendering lines as degenerate quads improves perf |
| 834 // when we have a mix | 1111 // when we have a mix |
| 835 | 1112 |
| 836 enum { | 1113 enum { |
| 837 // the edge effects share this stage with glyph rendering | 1114 // the edge effects share this stage with glyph rendering |
| 838 // (kGlyphMaskStage in GrTextContext) && SW path rendering | 1115 // (kGlyphMaskStage in GrTextContext) && SW path rendering |
| 839 // (kPathMaskStage in GrSWMaskHelper) | 1116 // (kPathMaskStage in GrSWMaskHelper) |
| 840 kEdgeEffectStage = GrPaint::kTotalStages, | 1117 kEdgeEffectStage = GrPaint::kTotalStages, |
| 841 }; | 1118 }; |
| 842 static const int kEdgeAttrIndex = 1; | 1119 static const int kEdgeAttrIndex = 1; |
| 843 | 1120 |
| 844 GrEffectRef* hairLineEffect = HairLineEdgeEffect::Create(); | 1121 GrEffectRef* hairLineEffect = HairLineEdgeEffect::Create(); |
| 845 GrEffectRef* hairQuadEffect = HairQuadEdgeEffect::Create(); | 1122 GrEffectRef* hairQuadEffect = HairQuadEdgeEffect::Create(); |
| 1123 GrEffectRef* hairConicEffect = HairConicEdgeEffect::Create(); | |
| 846 | 1124 |
| 847 // Check devBounds | 1125 // Check devBounds |
| 848 #if GR_DEBUG | 1126 #if GR_DEBUG |
| 849 SkRect tolDevBounds = devBounds; | 1127 SkRect tolDevBounds = devBounds; |
| 850 tolDevBounds.outset(SK_Scalar1 / 10000, SK_Scalar1 / 10000); | 1128 tolDevBounds.outset(SK_Scalar1 / 10000, SK_Scalar1 / 10000); |
| 851 SkRect actualBounds; | 1129 SkRect actualBounds; |
| 852 Vertex* verts = reinterpret_cast<Vertex*>(arg.vertices()); | 1130 Vertex* verts = reinterpret_cast<Vertex*>(arg.vertices()); |
| 853 int vCount = kVertsPerLineSeg * lineCnt + kVertsPerQuad * quadCnt; | 1131 int vCount = kVertsPerLineSeg * lineCnt + kVertsPerQuad * quadCnt + kVertsPe rConic * conicCnt; |
| 854 bool first = true; | 1132 bool first = true; |
| 855 for (int i = 0; i < vCount; ++i) { | 1133 for (int i = 0; i < vCount; ++i) { |
| 856 SkPoint pos = verts[i].fPos; | 1134 SkPoint pos = verts[i].fPos; |
| 857 // This is a hack to workaround the fact that we move some degenerate se gments offscreen. | 1135 // This is a hack to workaround the fact that we move some degenerate se gments offscreen. |
| 858 if (SK_ScalarMax == pos.fX) { | 1136 if (SK_ScalarMax == pos.fX) { |
| 859 continue; | 1137 continue; |
| 860 } | 1138 } |
| 861 drawState->getViewMatrix().mapPoints(&pos, 1); | 1139 drawState->getViewMatrix().mapPoints(&pos, 1); |
| 862 if (first) { | 1140 if (first) { |
| 863 actualBounds.set(pos.fX, pos.fY, pos.fX, pos.fY); | 1141 actualBounds.set(pos.fX, pos.fY, pos.fX, pos.fY); |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 882 target->drawIndexed(kTriangles_GrPrimitiveType, | 1160 target->drawIndexed(kTriangles_GrPrimitiveType, |
| 883 kVertsPerLineSeg*lines, // startV | 1161 kVertsPerLineSeg*lines, // startV |
| 884 0, // startI | 1162 0, // startI |
| 885 kVertsPerLineSeg*n, // vCount | 1163 kVertsPerLineSeg*n, // vCount |
| 886 kIdxsPerLineSeg*n, | 1164 kIdxsPerLineSeg*n, |
| 887 &devBounds); // iCount | 1165 &devBounds); // iCount |
| 888 lines += n; | 1166 lines += n; |
| 889 } | 1167 } |
| 890 } | 1168 } |
| 891 | 1169 |
| 892 target->setIndexSourceToBuffer(fQuadsIndexBuffer); | 1170 { |
| 893 int quads = 0; | 1171 GrDrawState::AutoRestoreEffects are(drawState); |
| 894 drawState->addCoverageEffect(hairQuadEffect, kEdgeAttrIndex)->unref(); | 1172 target->setIndexSourceToBuffer(fQuadsIndexBuffer); |
| 895 while (quads < quadCnt) { | 1173 int quads = 0; |
| 896 int n = GrMin(quadCnt - quads, kNumQuadsInIdxBuffer); | 1174 drawState->addCoverageEffect(hairQuadEffect, kEdgeAttrIndex)->unref(); |
| 897 target->drawIndexed(kTriangles_GrPrimitiveType, | 1175 while (quads < quadCnt) { |
| 898 4 * lineCnt + kVertsPerQuad*quads, // startV | 1176 int n = GrMin(quadCnt - quads, kNumQuadsInIdxBuffer); |
| 899 0, // startI | 1177 target->drawIndexed(kTriangles_GrPrimitiveType, |
| 900 kVertsPerQuad*n, // vCount | 1178 kVertsPerLineSeg * lineCnt + kVertsPerQuad*quads , // startV |
| 901 kIdxsPerQuad*n, // iCount | 1179 0, // startI |
| 902 &devBounds); | 1180 kVertsPerQuad*n, // vCount |
| 903 quads += n; | 1181 kIdxsPerQuad*n, // iCount |
| 1182 &devBounds); | |
| 1183 quads += n; | |
| 1184 } | |
| 1185 } | |
| 1186 | |
| 1187 { | |
| 1188 GrDrawState::AutoRestoreEffects are(drawState); | |
| 1189 target->setIndexSourceToBuffer(fConicsIndexBuffer); | |
| 1190 int conics = 0; | |
| 1191 drawState->addCoverageEffect(hairConicEffect, 1, 2)->unref(); | |
| 1192 // drawState->addCoverageEffect(hairConicEffect, kEdgeAttrIndex)->unref( ); | |
| 1193 while (conics < conicCnt) { | |
| 1194 int n = GrMin(conicCnt - conics, kNumConicsInIdxBuffer); | |
| 1195 target->drawIndexed(kTriangles_GrPrimitiveType, | |
| 1196 kVertsPerLineSeg*lineCnt + kVertsPerQuad*quadCnt + | |
| 1197 kVertsPerConic*conics, // startV | |
| 1198 0, // startI | |
| 1199 kVertsPerConic*n, // vCount | |
| 1200 kIdxsPerConic*n, // iCount | |
| 1201 &devBounds); | |
| 1202 conics += n; | |
| 1203 } | |
| 904 } | 1204 } |
| 905 target->resetIndexSource(); | 1205 target->resetIndexSource(); |
| 906 | 1206 |
| 907 return true; | 1207 return true; |
| 908 } | 1208 } |
| 1209 | |
| OLD | NEW |