1f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com/* 2f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com * Copyright 2011 Google Inc. 3f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com * 4f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com * Use of this source code is governed by a BSD-style license that can be 5f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com * found in the LICENSE file. 6f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com */ 7f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com 8aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#include "GrAAHairLinePathRenderer.h" 9aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 107bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt#include "GrBatch.h" 117bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt#include "GrBatchTarget.h" 1240ded3241894076237844325c015fcc724e9d443joshualitt#include "GrBatchTest.h" 13aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#include "GrContext.h" 145478d427c6e67c986a3390162c8fec77c466058ajoshualitt#include "GrDefaultGeoProcFactory.h" 15c26d94fd7dc0b00cd6d0e42d28285f4a38aff021bsalomon@google.com#include "GrDrawTargetCaps.h" 16aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#include "GrIndexBuffer.h" 17dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com#include "GrPathUtils.h" 188dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel#include "GrPipelineBuilder.h" 195478d427c6e67c986a3390162c8fec77c466058ajoshualitt#include "GrProcessor.h" 20ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon#include "GrResourceProvider.h" 2172e3ae486c66871c2043eac4f08d85d419fbca2absalomon#include "GrVertexBuffer.h" 22aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#include "SkGeometry.h" 2312b4e27ae1a29460e91a59f38122483e1faec697sugoi@google.com#include "SkStroke.h" 24aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#include "SkTemplates.h" 25aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 2607e1c3fd5030869c480c15ff30d36bd161718262commit-bot@chromium.org#include "effects/GrBezierEffect.h" 274647f9059825c062169d4d454c12640d82ae16c0bsalomon@google.com 28ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon#define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true> 29ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon 30aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com// quadratics are rendered as 5-sided polys in order to bound the 31aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com// AA stroke around the center-curve. See comments in push_quad_index_buffer and 325383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// bloat_quad. Quadratics and conics share an index buffer 33aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 34ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com// lines are rendered as: 35ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com// *______________* 36ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com// |\ -_______ /| 37ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com// | \ \ / | 38ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com// | *--------* | 39ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com// | / ______/ \ | 40ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com// */_-__________\* 41ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com// For: 6 vertices and 18 indices (for 6 triangles) 42681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com 435ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// Each quadratic is rendered as a five sided polygon. This poly bounds 445ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// the quadratic's bounding triangle but has been expanded so that the 455ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// 1-pixel wide area around the curve is inside the poly. 465ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// If a,b,c are the original control points then the poly a0,b0,c0,c1,a1 475ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// that is rendered would look like this: 485ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// b0 495ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// b 505ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// 515ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// a0 c0 525ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// a c 535ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// a1 c1 5414afb43b01e178b50674d16a5a62d2b7dbd600dbegdaniel// Each is drawn as three triangles ((a0,a1,b0), (b0,c1,c0), (a1,c1,b0)) 5514afb43b01e178b50674d16a5a62d2b7dbd600dbegdaniel// specified by these 9 indices: 565ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittstatic const uint16_t kQuadIdxBufPattern[] = { 575ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt 0, 1, 2, 585ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt 2, 4, 3, 595ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt 1, 4, 2 605ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt}; 615ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt 625ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittstatic const int kIdxsPerQuad = SK_ARRAY_COUNT(kQuadIdxBufPattern); 635ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittstatic const int kQuadNumVertices = 5; 645ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittstatic const int kQuadsNumInIdxBuffer = 256; 65ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonGR_DECLARE_STATIC_UNIQUE_KEY(gQuadsIndexBufferKey); 66ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon 67ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonstatic const GrIndexBuffer* ref_quads_index_buffer(GrResourceProvider* resourceProvider) { 68ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon GR_DEFINE_STATIC_UNIQUE_KEY(gQuadsIndexBufferKey); 69ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon return resourceProvider->refOrCreateInstancedIndexBuffer( 70ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon kQuadIdxBufPattern, kIdxsPerQuad, kQuadsNumInIdxBuffer, kQuadNumVertices, 71ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon gQuadsIndexBufferKey); 72ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon} 735ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt 745ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt 755ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// Each line segment is rendered as two quads and two triangles. 765ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// p0 and p1 have alpha = 1 while all other points have alpha = 0. 775ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// The four external points are offset 1 pixel perpendicular to the 785ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// line and half a pixel parallel to the line. 795ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// 805ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// p4 p5 815ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// p0 p1 825ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// p2 p3 835ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// 845ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// Each is drawn as six triangles specified by these 18 indices: 855ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt 865ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittstatic const uint16_t kLineSegIdxBufPattern[] = { 875ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt 0, 1, 3, 885ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt 0, 3, 2, 895ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt 0, 4, 5, 905ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt 0, 5, 1, 915ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt 0, 2, 4, 925ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt 1, 5, 3 935ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt}; 945ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt 955ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittstatic const int kIdxsPerLineSeg = SK_ARRAY_COUNT(kLineSegIdxBufPattern); 965ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittstatic const int kLineSegNumVertices = 6; 975ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittstatic const int kLineSegsNumInIdxBuffer = 256; 98aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 99ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonGR_DECLARE_STATIC_UNIQUE_KEY(gLinesIndexBufferKey); 100aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 101ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonstatic const GrIndexBuffer* ref_lines_index_buffer(GrResourceProvider* resourceProvider) { 102ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon GR_DEFINE_STATIC_UNIQUE_KEY(gLinesIndexBufferKey); 103ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon return resourceProvider->refOrCreateInstancedIndexBuffer( 104ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon kLineSegIdxBufPattern, kIdxsPerLineSeg, kLineSegsNumInIdxBuffer, kLineSegNumVertices, 105ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon gLinesIndexBufferKey); 106aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 107aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 108aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com// Takes 178th time of logf on Z600 / VC2010 109ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonstatic int get_float_exp(float x) { 110aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com GR_STATIC_ASSERT(sizeof(int) == sizeof(float)); 111515dcd36032997ce335daa0163c6d67e851bcad1commit-bot@chromium.org#ifdef SK_DEBUG 112aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com static bool tested; 113aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com if (!tested) { 114aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com tested = true; 115f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(get_float_exp(0.25f) == -2); 116f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(get_float_exp(0.3f) == -2); 117f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(get_float_exp(0.5f) == -1); 118f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(get_float_exp(1.f) == 0); 119f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(get_float_exp(2.f) == 1); 120f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(get_float_exp(2.5f) == 1); 121f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(get_float_exp(8.f) == 3); 122f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(get_float_exp(100.f) == 6); 123f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(get_float_exp(1000.f) == 9); 124f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(get_float_exp(1024.f) == 10); 125f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(get_float_exp(3000000.f) == 21); 126aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 127aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#endif 1282ec7280a178ad3dcfd2e645bc330eeb04a84bfcfbsalomon@google.com const int* iptr = (const int*)&x; 1292ec7280a178ad3dcfd2e645bc330eeb04a84bfcfbsalomon@google.com return (((*iptr) & 0x7f800000) >> 23) - 127; 130aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 131aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 1325383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// Uses the max curvature function for quads to estimate 1335383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// where to chop the conic. If the max curvature is not 1345383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// found along the curve segment it will return 1 and 1353f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// dst[0] is the original conic. If it returns 2 the dst[0] 1365383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// and dst[1] are the two new conics. 137ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonstatic int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) { 1385383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com SkScalar t = SkFindQuadMaxCurvature(src); 1395383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com if (t == 0) { 1405383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com if (dst) { 1415383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com dst[0].set(src, weight); 1425383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 1435383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com return 1; 1445383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } else { 1455383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com if (dst) { 1465383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com SkConic conic; 1475383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com conic.set(src, weight); 1485383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com conic.chopAt(t, dst); 1495383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 1505383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com return 2; 1515383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 1525383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com} 1535383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 1543f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// Calls split_conic on the entire conic and then once more on each subsection. 1553f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// Most cases will result in either 1 conic (chop point is not within t range) 1563f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// or 3 points (split once and then one subsection is split again). 157ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonstatic int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) { 1583f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com SkConic dstTemp[2]; 1593f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com int conicCnt = split_conic(src, dstTemp, weight); 1603f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com if (2 == conicCnt) { 1613f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW); 1623f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dstTemp[1].fW); 1633f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com } else { 1643f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com dst[0] = dstTemp[0]; 1653f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com } 1663f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com return conicCnt; 1673f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com} 1683f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com 1695383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// returns 0 if quad/conic is degen or close to it 1705383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// in this case approx the path with lines 1715383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// otherwise returns 1 172ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonstatic int is_degen_quad_or_conic(const SkPoint p[3], SkScalar* dsqd) { 173876f48b6cdae5a77770304ae77f42aff530fa90djvanverth static const SkScalar gDegenerateToLineTol = GrPathUtils::kDefaultTolerance; 1745383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com static const SkScalar gDegenerateToLineTolSqd = 1755383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol); 1765383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 1775383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd || 1785383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) { 1795383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com return 1; 1805383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 1815383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 1826364807151ddf51c4197603aa185b3336f325357joshualitt *dsqd = p[1].distanceToLineBetweenSqd(p[0], p[2]); 1836364807151ddf51c4197603aa185b3336f325357joshualitt if (*dsqd < gDegenerateToLineTolSqd) { 1845383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com return 1; 1855383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 1865383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 1875383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com if (p[2].distanceToLineBetweenSqd(p[1], p[0]) < gDegenerateToLineTolSqd) { 1885383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com return 1; 1895383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 1905383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com return 0; 1915383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com} 1925383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 193ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonstatic int is_degen_quad_or_conic(const SkPoint p[3]) { 1946364807151ddf51c4197603aa185b3336f325357joshualitt SkScalar dsqd; 1956364807151ddf51c4197603aa185b3336f325357joshualitt return is_degen_quad_or_conic(p, &dsqd); 1966364807151ddf51c4197603aa185b3336f325357joshualitt} 1976364807151ddf51c4197603aa185b3336f325357joshualitt 198aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com// we subdivide the quads to avoid huge overfill 199aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com// if it returns -1 then should be drawn as lines 200ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonstatic int num_quad_subdivs(const SkPoint p[3]) { 2016364807151ddf51c4197603aa185b3336f325357joshualitt SkScalar dsqd; 2026364807151ddf51c4197603aa185b3336f325357joshualitt if (is_degen_quad_or_conic(p, &dsqd)) { 203aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com return -1; 204aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 205aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 206aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // tolerance of triangle height in pixels 207aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // tuned on windows Quadro FX 380 / Z600 208aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // trade off of fill vs cpu time on verts 209aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // maybe different when do this using gpu (geo or tess shaders) 210aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com static const SkScalar gSubdivTol = 175 * SK_Scalar1; 211aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 2127460b378d68217167013ca889a4cdcae742908e7robertphillips@google.com if (dsqd <= SkScalarMul(gSubdivTol, gSubdivTol)) { 213aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com return 0; 214aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } else { 21587379e17c5e95c6fe0d88b3b9ae134355cfafc66robertphillips@google.com static const int kMaxSub = 4; 216aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // subdividing the quad reduces d by 4. so we want x = log4(d/tol) 217aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // = log4(d*d/tol*tol)/2 218aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // = log2(d*d/tol*tol) 219aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 220aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // +1 since we're ignoring the mantissa contribution. 221aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com int log = get_float_exp(dsqd/(gSubdivTol*gSubdivTol)) + 1; 222972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org log = SkTMin(SkTMax(0, log), kMaxSub); 223aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com return log; 224aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 225aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 226aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 227dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com/** 228dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * Generates the lines and quads to be rendered. Lines are always recorded in 229dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * device space. We will do a device space bloat to account for the 1pixel 230dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * thickness. 231dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * Quads are recorded in device space unless m contains 232dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * perspective, then in they are in src space. We do this because we will 233dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * subdivide large quads to reduce over-fill. This subdivision has to be 234dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * performed before applying the perspective matrix. 235dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com */ 236ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonstatic int gather_lines_and_quads(const SkPath& path, 237ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon const SkMatrix& m, 238ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon const SkIRect& devClipBounds, 239ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon GrAAHairLinePathRenderer::PtArray* lines, 240ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon GrAAHairLinePathRenderer::PtArray* quads, 241ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon GrAAHairLinePathRenderer::PtArray* conics, 242ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon GrAAHairLinePathRenderer::IntArray* quadSubdivCnts, 243ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon GrAAHairLinePathRenderer::FloatArray* conicWeights) { 244aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkPath::Iter iter(path, false); 245aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 246aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com int totalQuadCount = 0; 247fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org SkRect bounds; 248fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org SkIRect ibounds; 249dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com 250dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com bool persp = m.hasPerspective(); 251dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com 252aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com for (;;) { 253972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org SkPoint pathPts[4]; 254972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org SkPoint devPts[4]; 255912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org SkPath::Verb verb = iter.next(pathPts); 25694b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com switch (verb) { 2575383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com case SkPath::kConic_Verb: { 2583f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com SkConic dst[4]; 2593f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com // We chop the conics to create tighter clipping to hide error 2603f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com // that appears near max curvature of very thin conics. Thin 2613f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com // hyperbolas with high weight still show error. 2625383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com int conicCnt = chop_conic(pathPts, dst, iter.conicWeight()); 2635383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com for (int i = 0; i < conicCnt; ++i) { 2645383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com SkPoint* chopPnts = dst[i].fPts; 2655383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com m.mapPoints(devPts, chopPnts, 3); 2665383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com bounds.setBounds(devPts, 3); 2675383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com bounds.outset(SK_Scalar1, SK_Scalar1); 2685383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com bounds.roundOut(&ibounds); 2695383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com if (SkIRect::Intersects(devClipBounds, ibounds)) { 2705383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com if (is_degen_quad_or_conic(devPts)) { 2715383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com SkPoint* pts = lines->push_back_n(4); 2725383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com pts[0] = devPts[0]; 2735383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com pts[1] = devPts[1]; 2745383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com pts[2] = devPts[1]; 2755383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com pts[3] = devPts[2]; 2765383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } else { 2775383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com // when in perspective keep conics in src space 2785383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com SkPoint* cPts = persp ? chopPnts : devPts; 2795383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com SkPoint* pts = conics->push_back_n(3); 2805383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com pts[0] = cPts[0]; 2815383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com pts[1] = cPts[1]; 2825383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com pts[2] = cPts[2]; 2835383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com conicWeights->push_back() = dst[i].fW; 2845383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 2855383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 2865383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 287277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com break; 2885383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 2895383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com case SkPath::kMove_Verb: 290aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com break; 29194b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com case SkPath::kLine_Verb: 292912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org m.mapPoints(devPts, pathPts, 2); 293dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com bounds.setBounds(devPts, 2); 294aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com bounds.outset(SK_Scalar1, SK_Scalar1); 295aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com bounds.roundOut(&ibounds); 2967b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com if (SkIRect::Intersects(devClipBounds, ibounds)) { 297a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com SkPoint* pts = lines->push_back_n(2); 298a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com pts[0] = devPts[0]; 299a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com pts[1] = devPts[1]; 300aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 301aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com break; 302912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org case SkPath::kQuad_Verb: { 303912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org SkPoint choppedPts[5]; 304912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org // Chopping the quad helps when the quad is either degenerate or nearly degenerate. 305912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org // When it is degenerate it allows the approximation with lines to work since the 306912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org // chop point (if there is one) will be at the parabola's vertex. In the nearly 307912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org // degenerate the QuadUVMatrix computed for the points is almost singular which 308912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org // can cause rendering artifacts. 309912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org int n = SkChopQuadAtMaxCurvature(pathPts, choppedPts); 310912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org for (int i = 0; i < n; ++i) { 311912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org SkPoint* quadPts = choppedPts + i * 2; 312912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org m.mapPoints(devPts, quadPts, 3); 313912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org bounds.setBounds(devPts, 3); 314912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org bounds.outset(SK_Scalar1, SK_Scalar1); 315912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org bounds.roundOut(&ibounds); 316912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org 317912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org if (SkIRect::Intersects(devClipBounds, ibounds)) { 318912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org int subdiv = num_quad_subdivs(devPts); 319f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(subdiv >= -1); 320912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org if (-1 == subdiv) { 321912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org SkPoint* pts = lines->push_back_n(4); 322912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org pts[0] = devPts[0]; 323912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org pts[1] = devPts[1]; 324912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org pts[2] = devPts[1]; 325912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org pts[3] = devPts[2]; 326912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org } else { 327912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org // when in perspective keep quads in src space 328912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org SkPoint* qPts = persp ? quadPts : devPts; 329912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org SkPoint* pts = quads->push_back_n(3); 330912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org pts[0] = qPts[0]; 331912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org pts[1] = qPts[1]; 332912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org pts[2] = qPts[2]; 333912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org quadSubdivCnts->push_back() = subdiv; 334912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org totalQuadCount += 1 << subdiv; 335912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org } 336aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 337aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 338a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com break; 339912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org } 34094b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com case SkPath::kCubic_Verb: 341912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org m.mapPoints(devPts, pathPts, 4); 342dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com bounds.setBounds(devPts, 4); 343aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com bounds.outset(SK_Scalar1, SK_Scalar1); 344aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com bounds.roundOut(&ibounds); 3457b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com if (SkIRect::Intersects(devClipBounds, ibounds)) { 34692669014aa7ab821cdc09cc9ad610316eb16b490bsalomon@google.com PREALLOC_PTARRAY(32) q; 347a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com // we don't need a direction if we aren't constraining the subdivision 348a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com static const SkPath::Direction kDummyDir = SkPath::kCCW_Direction; 34969cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com // We convert cubics to quadratics (for now). 35069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com // In perspective have to do conversion in src space. 351dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com if (persp) { 352fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com SkScalar tolScale = 353dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com GrPathUtils::scaleToleranceToSrc(SK_Scalar1, m, 354dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com path.getBounds()); 355912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org GrPathUtils::convertCubicToQuads(pathPts, tolScale, false, kDummyDir, &q); 356dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com } else { 357a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com GrPathUtils::convertCubicToQuads(devPts, SK_Scalar1, false, kDummyDir, &q); 358dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com } 359aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com for (int i = 0; i < q.count(); i += 3) { 360dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com SkPoint* qInDevSpace; 361dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // bounds has to be calculated in device space, but q is 362dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // in src space when there is perspective. 363dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com if (persp) { 364dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com m.mapPoints(devPts, &q[i], 3); 365dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com bounds.setBounds(devPts, 3); 366dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com qInDevSpace = devPts; 367dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com } else { 368dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com bounds.setBounds(&q[i], 3); 369dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com qInDevSpace = &q[i]; 370dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com } 371aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com bounds.outset(SK_Scalar1, SK_Scalar1); 372aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com bounds.roundOut(&ibounds); 3737b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com if (SkIRect::Intersects(devClipBounds, ibounds)) { 374dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com int subdiv = num_quad_subdivs(qInDevSpace); 375f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(subdiv >= -1); 376aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com if (-1 == subdiv) { 377a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com SkPoint* pts = lines->push_back_n(4); 378dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // lines should always be in device coords 379a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com pts[0] = qInDevSpace[0]; 380a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com pts[1] = qInDevSpace[1]; 381a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com pts[2] = qInDevSpace[1]; 382a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com pts[3] = qInDevSpace[2]; 383aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } else { 384a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com SkPoint* pts = quads->push_back_n(3); 385dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // q is already in src space when there is no 386dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // perspective and dev coords otherwise. 387a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com pts[0] = q[0 + i]; 388a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com pts[1] = q[1 + i]; 389a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com pts[2] = q[2 + i]; 390aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com quadSubdivCnts->push_back() = subdiv; 391aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com totalQuadCount += 1 << subdiv; 392aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 393aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 394aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 395aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 396a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com break; 39794b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com case SkPath::kClose_Verb: 398aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com break; 39994b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com case SkPath::kDone_Verb: 400aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com return totalQuadCount; 401aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 402aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 403aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 404aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 405681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.comstruct LineVertex { 406972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org SkPoint fPos; 407e27065ae243575f6d5d545909ad3030773c14db8egdaniel float fCoverage; 408681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com}; 4097475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com 410681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.comstruct BezierVertex { 411972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org SkPoint fPos; 412aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com union { 413aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com struct { 4143f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com SkScalar fK; 4153f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com SkScalar fL; 4163f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com SkScalar fM; 4175383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } fConic; 418972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org SkVector fQuadCoord; 419aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com struct { 4203f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com SkScalar fBogus[4]; 421aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com }; 422aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com }; 423aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com}; 4245383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 425972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.orgGR_STATIC_ASSERT(sizeof(BezierVertex) == 3 * sizeof(SkPoint)); 426aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 427ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonstatic void intersect_lines(const SkPoint& ptA, const SkVector& normA, 428ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon const SkPoint& ptB, const SkVector& normB, 429ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon SkPoint* result) { 430aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 431aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkScalar lineAW = -normA.dot(ptA); 432aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkScalar lineBW = -normB.dot(ptB); 433aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 434aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkScalar wInv = SkScalarMul(normA.fX, normB.fY) - 4355383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com SkScalarMul(normA.fY, normB.fX); 436aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com wInv = SkScalarInvert(wInv); 437aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 438aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com result->fX = SkScalarMul(normA.fY, lineBW) - SkScalarMul(lineAW, normB.fY); 439aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com result->fX = SkScalarMul(result->fX, wInv); 440fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 441aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com result->fY = SkScalarMul(lineAW, normB.fX) - SkScalarMul(normA.fX, lineBW); 442aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com result->fY = SkScalarMul(result->fY, wInv); 443aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 444aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 445ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonstatic void set_uv_quad(const SkPoint qpts[3], BezierVertex verts[kQuadNumVertices]) { 44634b05ca3799f4adc2994d57a22d78ae1bdf6fb4aegdaniel@google.com // this should be in the src space, not dev coords, when we have perspective 44734b05ca3799f4adc2994d57a22d78ae1bdf6fb4aegdaniel@google.com GrPathUtils::QuadUVMatrix DevToUV(qpts); 4485ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt DevToUV.apply<kQuadNumVertices, sizeof(BezierVertex), sizeof(SkPoint)>(verts); 44934b05ca3799f4adc2994d57a22d78ae1bdf6fb4aegdaniel@google.com} 45034b05ca3799f4adc2994d57a22d78ae1bdf6fb4aegdaniel@google.com 451ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonstatic void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, 452ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon const SkMatrix* toSrc, BezierVertex verts[kQuadNumVertices]) { 453f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(!toDevice == !toSrc); 454aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // original quad is specified by tri a,b,c 455dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com SkPoint a = qpts[0]; 456dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com SkPoint b = qpts[1]; 457dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com SkPoint c = qpts[2]; 458aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 459dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com if (toDevice) { 460dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com toDevice->mapPoints(&a, 1); 461dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com toDevice->mapPoints(&b, 1); 462dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com toDevice->mapPoints(&c, 1); 463dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com } 464dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // make a new poly where we replace a and c by a 1-pixel wide edges orthog 465dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // to edges ab and bc: 466dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // 467dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // before | after 468dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // | b0 469dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // b | 470dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // | 471dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // | a0 c0 472dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // a c | a1 c1 473dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // 474dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // edges a0->b0 and b0->c0 are parallel to original edges a->b and b->c, 475dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // respectively. 476681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com BezierVertex& a0 = verts[0]; 477681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com BezierVertex& a1 = verts[1]; 478681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com BezierVertex& b0 = verts[2]; 479681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com BezierVertex& c0 = verts[3]; 480681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com BezierVertex& c1 = verts[4]; 481dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com 482aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkVector ab = b; 483aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com ab -= a; 484aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkVector ac = c; 485aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com ac -= a; 486aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkVector cb = b; 487aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com cb -= c; 488aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 489aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // We should have already handled degenerates 490f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(ab.length() > 0 && cb.length() > 0); 491aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 492aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com ab.normalize(); 493aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkVector abN; 494aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com abN.setOrthog(ab, SkVector::kLeft_Side); 495aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com if (abN.dot(ac) > 0) { 496aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com abN.negate(); 497aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 498aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 499aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com cb.normalize(); 500aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkVector cbN; 501aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com cbN.setOrthog(cb, SkVector::kLeft_Side); 502aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com if (cbN.dot(ac) < 0) { 503aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com cbN.negate(); 504aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 505aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 506aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com a0.fPos = a; 507aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com a0.fPos += abN; 508aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com a1.fPos = a; 509aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com a1.fPos -= abN; 510aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 511aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com c0.fPos = c; 512aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com c0.fPos += cbN; 513aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com c1.fPos = c; 514aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com c1.fPos -= cbN; 515aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 516aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos); 517aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 518dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com if (toSrc) { 5195ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(BezierVertex), kQuadNumVertices); 520dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com } 521aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 522aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 5233f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// Equations based off of Loop-Blinn Quadratic GPU Rendering 5245383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// Input Parametric: 5255383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// 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) 5265383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// Output Implicit: 5273f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// f(x, y, w) = f(P) = K^2 - LM 5283f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// K = dot(k, P), L = dot(l, P), M = dot(m, P) 529139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org// k, l, m are calculated in function GrPathUtils::getConicKLM 530ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonstatic void set_conic_coeffs(const SkPoint p[3], BezierVertex verts[kQuadNumVertices], 531ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon const SkScalar weight) { 532139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org SkScalar klm[9]; 5333f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com 534139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org GrPathUtils::getConicKLM(p, weight, klm); 5355383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 5365ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt for (int i = 0; i < kQuadNumVertices; ++i) { 5373f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com const SkPoint pnt = verts[i].fPos; 538139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org verts[i].fConic.fK = pnt.fX * klm[0] + pnt.fY * klm[1] + klm[2]; 539139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org verts[i].fConic.fL = pnt.fX * klm[3] + pnt.fY * klm[4] + klm[5]; 540139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org verts[i].fConic.fM = pnt.fX * klm[6] + pnt.fY * klm[7] + klm[8]; 5415383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 5425383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com} 5435383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 544ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonstatic void add_conics(const SkPoint p[3], 545ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon const SkScalar weight, 546ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon const SkMatrix* toDevice, 547ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon const SkMatrix* toSrc, 548ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon BezierVertex** vert) { 5497bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt bloat_quad(p, toDevice, toSrc, *vert); 5505383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com set_conic_coeffs(p, *vert, weight); 5515ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt *vert += kQuadNumVertices; 5525383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com} 5535383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 554ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonstatic void add_quads(const SkPoint p[3], 555ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon int subdiv, 556ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon const SkMatrix* toDevice, 557ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon const SkMatrix* toSrc, 558ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon BezierVertex** vert) { 559f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(subdiv >= 0); 560aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com if (subdiv) { 561aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkPoint newP[5]; 562aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkChopQuadAtHalf(p, newP); 5637bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt add_quads(newP + 0, subdiv-1, toDevice, toSrc, vert); 5647bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt add_quads(newP + 2, subdiv-1, toDevice, toSrc, vert); 565aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } else { 5667bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt bloat_quad(p, toDevice, toSrc, *vert); 56734b05ca3799f4adc2994d57a22d78ae1bdf6fb4aegdaniel@google.com set_uv_quad(p, *vert); 5685ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt *vert += kQuadNumVertices; 569aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 570aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 571aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 572ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomonstatic void add_line(const SkPoint p[2], 573ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon const SkMatrix* toSrc, 574ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon uint8_t coverage, 575ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon LineVertex** vert) { 576aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com const SkPoint& a = p[0]; 577aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com const SkPoint& b = p[1]; 578aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 579ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com SkVector ortho, vec = b; 580ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com vec -= a; 581ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com 582ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com if (vec.setLength(SK_ScalarHalf)) { 583ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com // Create a vector orthogonal to 'vec' and of unit length 584ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com ortho.fX = 2.0f * vec.fY; 585ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com ortho.fY = -2.0f * vec.fX; 586ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com 587e27065ae243575f6d5d545909ad3030773c14db8egdaniel float floatCoverage = GrNormalizeByteToFloat(coverage); 588e27065ae243575f6d5d545909ad3030773c14db8egdaniel 589ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com (*vert)[0].fPos = a; 590e27065ae243575f6d5d545909ad3030773c14db8egdaniel (*vert)[0].fCoverage = floatCoverage; 591ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com (*vert)[1].fPos = b; 592e27065ae243575f6d5d545909ad3030773c14db8egdaniel (*vert)[1].fCoverage = floatCoverage; 593ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com (*vert)[2].fPos = a - vec + ortho; 594ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com (*vert)[2].fCoverage = 0; 595ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com (*vert)[3].fPos = b + vec + ortho; 596ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com (*vert)[3].fCoverage = 0; 597ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com (*vert)[4].fPos = a - vec - ortho; 598ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com (*vert)[4].fCoverage = 0; 599ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com (*vert)[5].fPos = b + vec - ortho; 600ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com (*vert)[5].fCoverage = 0; 601aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 60249f085dddff10473b6ebf832a974288300224e60bsalomon if (toSrc) { 603dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com toSrc->mapPointsWithStride(&(*vert)->fPos, 604681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com sizeof(LineVertex), 6055ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt kLineSegNumVertices); 606dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com } 607aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } else { 608aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // just make it degenerate and likely offscreen 6095ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt for (int i = 0; i < kLineSegNumVertices; ++i) { 610681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com (*vert)[i].fPos.set(SK_ScalarMax, SK_ScalarMax); 611681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com } 612aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 613aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 6145ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt *vert += kLineSegNumVertices; 615aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 616aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 61790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org/////////////////////////////////////////////////////////////////////////////// 61890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 6199853ccef19c200be93a6211f32589fa82a53067cjoshualittbool GrAAHairLinePathRenderer::canDrawPath(const GrDrawTarget* target, 6208dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel const GrPipelineBuilder* pipelineBuilder, 6218059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt const SkMatrix& viewMatrix, 6229853ccef19c200be93a6211f32589fa82a53067cjoshualitt const SkPath& path, 6231899651ffc459f5462aa989cd6d08507947b67e4kkinnunen const GrStrokeInfo& stroke, 6248a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com bool antiAlias) const { 625e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org if (!antiAlias) { 626e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org return false; 627e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org } 628e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org 6298059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt if (!IsStrokeHairlineOrEquivalent(stroke, viewMatrix, NULL)) { 630c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com return false; 631c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com } 632c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com 633e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com if (SkPath::kLine_SegmentMask == path.getSegmentMasks() || 634e9c0fc616d2a1632c285885b9b656b68ca8d4f24jvanverth target->caps()->shaderCaps()->shaderDerivativeSupport()) { 6353f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com return true; 636c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com } 6373f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com return false; 638c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com} 639aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 640681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.comtemplate <class VertexType> 6418059eb9f6e24ed609393fbda4ad71edea03ac258joshualittbool check_bounds(const SkMatrix& viewMatrix, const SkRect& devBounds, void* vertices, int vCount) 642681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com{ 6431dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com SkRect tolDevBounds = devBounds; 644b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org // The bounds ought to be tight, but in perspective the below code runs the verts 645b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org // through the view matrix to get back to dev coords, which can introduce imprecision. 6468059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt if (viewMatrix.hasPerspective()) { 647b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org tolDevBounds.outset(SK_Scalar1 / 1000, SK_Scalar1 / 1000); 648b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org } else { 649b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org // Non-persp matrices cause this path renderer to draw in device space. 6508059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt SkASSERT(viewMatrix.isIdentity()); 651b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org } 6521dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com SkRect actualBounds; 6537475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com 654681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com VertexType* verts = reinterpret_cast<VertexType*>(vertices); 6551dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com bool first = true; 6561dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com for (int i = 0; i < vCount; ++i) { 6571dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com SkPoint pos = verts[i].fPos; 6581dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com // This is a hack to workaround the fact that we move some degenerate segments offscreen. 6591dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com if (SK_ScalarMax == pos.fX) { 6601dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com continue; 6611dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com } 6628059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt viewMatrix.mapPoints(&pos, 1); 6631dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com if (first) { 6641dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com actualBounds.set(pos.fX, pos.fY, pos.fX, pos.fY); 6651dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com first = false; 6661dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com } else { 6671dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com actualBounds.growToInclude(pos.fX, pos.fY); 6681dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com } 6691dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com } 6701dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com if (!first) { 671681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com return tolDevBounds.contains(actualBounds); 6721dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com } 6737475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com 674681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com return true; 675681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com} 6761dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com 6777bc18b75ee473cd90c5577270e378f99cedd4ab9joshualittclass AAHairlineBatch : public GrBatch { 6787bc18b75ee473cd90c5577270e378f99cedd4ab9joshualittpublic: 6797bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt struct Geometry { 6807bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt GrColor fColor; 6817bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt uint8_t fCoverage; 6827bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt SkMatrix fViewMatrix; 6837bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt SkPath fPath; 6847bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt SkIRect fDevClipBounds; 6857bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt }; 6867bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 687ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon static GrBatch* Create(const Geometry& geometry) { 688ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon return SkNEW_ARGS(AAHairlineBatch, (geometry)); 689658d55cd6121c67488aaf5d0832c9712737f26a5joshualitt } 690658d55cd6121c67488aaf5d0832c9712737f26a5joshualitt 69136352bf5e38f45a70ee4f4fc132a38048d38206dmtklein const char* name() const override { return "AAHairlineBatch"; } 6927bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 69336352bf5e38f45a70ee4f4fc132a38048d38206dmtklein void getInvariantOutputColor(GrInitInvariantOutput* out) const override { 6947bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt // When this is called on a batch, there is only one geometry bundle 6957bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt out->setKnownFourComponents(fGeoData[0].fColor); 6967bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt } 69736352bf5e38f45a70ee4f4fc132a38048d38206dmtklein void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override { 6987bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt out->setUnknownSingleComponent(); 6997bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt } 7007bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 70136352bf5e38f45a70ee4f4fc132a38048d38206dmtklein void initBatchTracker(const GrPipelineInfo& init) override { 7027bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt // Handle any color overrides 7037bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt if (init.fColorIgnored) { 7047bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt fGeoData[0].fColor = GrColor_ILLEGAL; 7057bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt } else if (GrColor_ILLEGAL != init.fOverrideColor) { 7067bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt fGeoData[0].fColor = init.fOverrideColor; 7077bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt } 7087bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 7097bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt // setup batch properties 7107bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt fBatch.fColorIgnored = init.fColorIgnored; 7117bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt fBatch.fColor = fGeoData[0].fColor; 7127bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt fBatch.fUsesLocalCoords = init.fUsesLocalCoords; 7137bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt fBatch.fCoverageIgnored = init.fCoverageIgnored; 7147bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt fBatch.fCoverage = fGeoData[0].fCoverage; 7157bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt } 7167bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 71736352bf5e38f45a70ee4f4fc132a38048d38206dmtklein void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override; 7187bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 7197bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; } 7207bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 7217bc18b75ee473cd90c5577270e378f99cedd4ab9joshualittprivate: 7227bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt typedef SkTArray<SkPoint, true> PtArray; 7237bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt typedef SkTArray<int, true> IntArray; 7247bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt typedef SkTArray<float, true> FloatArray; 725658d55cd6121c67488aaf5d0832c9712737f26a5joshualitt 726ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon AAHairlineBatch(const Geometry& geometry) { 7277bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt this->initClassID<AAHairlineBatch>(); 7287bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt fGeoData.push_back(geometry); 72999c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt 73099c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt // compute bounds 73199c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt fBounds = geometry.fPath.getBounds(); 73299c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt geometry.fViewMatrix.mapRect(&fBounds); 7334c977868bbe100d6d95f9e53cf176d611eceb3dcjoshualitt 7344c977868bbe100d6d95f9e53cf176d611eceb3dcjoshualitt // This is b.c. hairlines are notionally infinitely thin so without expansion 7354c977868bbe100d6d95f9e53cf176d611eceb3dcjoshualitt // two overlapping lines could be reordered even though they hit the same pixels. 7364c977868bbe100d6d95f9e53cf176d611eceb3dcjoshualitt fBounds.outset(0.5f, 0.5f); 7377bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt } 7387bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 73936352bf5e38f45a70ee4f4fc132a38048d38206dmtklein bool onCombineIfPossible(GrBatch* t) override { 7407bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt AAHairlineBatch* that = t->cast<AAHairlineBatch>(); 7417bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 7427bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt if (this->viewMatrix().hasPerspective() != that->viewMatrix().hasPerspective()) { 7437bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt return false; 7447bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt } 7457bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 7467bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt // We go to identity if we don't have perspective 7477bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt if (this->viewMatrix().hasPerspective() && 7487bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt !this->viewMatrix().cheapEqualTo(that->viewMatrix())) { 7497bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt return false; 7507bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt } 7517bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 7527bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt // TODO we can actually batch hairlines if they are the same color in a kind of bulk method 7537bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt // but we haven't implemented this yet 7547bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt // TODO investigate going to vertex color and coverage? 7557bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt if (this->coverage() != that->coverage()) { 7567bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt return false; 7577bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt } 7587bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 7597bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt if (this->color() != that->color()) { 7607bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt return false; 7617bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt } 7627bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 7637bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt SkASSERT(this->usesLocalCoords() == that->usesLocalCoords()); 7647bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) { 7657bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt return false; 7667bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt } 7677bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 7687bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin()); 76999c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt this->joinBounds(that->bounds()); 7707bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt return true; 7717bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt } 7727bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 7737bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt GrColor color() const { return fBatch.fColor; } 7747bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt uint8_t coverage() const { return fBatch.fCoverage; } 7757bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } 7767bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; } 7777bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 7787bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt struct BatchTracker { 7797bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt GrColor fColor; 7807bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt uint8_t fCoverage; 7817bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt SkRect fDevBounds; 7827bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt bool fUsesLocalCoords; 7837bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt bool fColorIgnored; 7847bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt bool fCoverageIgnored; 7857bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt }; 7867bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 7877bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt BatchTracker fBatch; 7887bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt SkSTArray<1, Geometry, true> fGeoData; 7897bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt}; 7907bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 7917bc18b75ee473cd90c5577270e378f99cedd4ab9joshualittvoid AAHairlineBatch::generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) { 7927bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt // Setup the viewmatrix and localmatrix for the GrGeometryProcessor. 7937bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt SkMatrix invert; 7947bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt if (!this->viewMatrix().invert(&invert)) { 7957bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt return; 7967bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt } 7977bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 7987bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt // we will transform to identity space if the viewmatrix does not have perspective 7997bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt bool hasPerspective = this->viewMatrix().hasPerspective(); 8007bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt const SkMatrix* geometryProcessorViewM = &SkMatrix::I(); 8017bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt const SkMatrix* geometryProcessorLocalM = &invert; 8027bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt const SkMatrix* toDevice = NULL; 8037bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt const SkMatrix* toSrc = NULL; 8047bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt if (hasPerspective) { 8057bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt geometryProcessorViewM = &this->viewMatrix(); 8067bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt geometryProcessorLocalM = &SkMatrix::I(); 8077bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt toDevice = &this->viewMatrix(); 8087bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt toSrc = &invert; 8097bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt } 8107bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 8117bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt // Setup geometry processors for worst case 8127bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt uint32_t gpFlags = GrDefaultGeoProcFactory::kPosition_GPType | 8137bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt GrDefaultGeoProcFactory::kCoverage_GPType; 8147bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 8157bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt SkAutoTUnref<const GrGeometryProcessor> lineGP( 8167bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt GrDefaultGeoProcFactory::Create(gpFlags, 8177bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt this->color(), 8187bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt *geometryProcessorViewM, 8197bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt *geometryProcessorLocalM, 8207bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt this->coverage())); 8217bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 8227bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt SkAutoTUnref<const GrGeometryProcessor> quadGP( 8237bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt GrQuadEffect::Create(this->color(), 8247bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt *geometryProcessorViewM, 8257bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt kHairlineAA_GrProcessorEdgeType, 8267bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt batchTarget->caps(), 8277bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt *geometryProcessorLocalM, 8287bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt this->coverage())); 8297bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 8307bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt SkAutoTUnref<const GrGeometryProcessor> conicGP( 8317bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt GrConicEffect::Create(this->color(), 8327bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt *geometryProcessorViewM, 8337bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt kHairlineAA_GrProcessorEdgeType, 8347bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt batchTarget->caps(), 8357bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt *geometryProcessorLocalM, 8367bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt this->coverage())); 8377bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 8387bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt // This is hand inlined for maximum performance. 83946c77f76be8cbcddccc1ae0058d589cbbdb468f7joshualitt PREALLOC_PTARRAY(128) lines; 84046c77f76be8cbcddccc1ae0058d589cbbdb468f7joshualitt PREALLOC_PTARRAY(128) quads; 84146c77f76be8cbcddccc1ae0058d589cbbdb468f7joshualitt PREALLOC_PTARRAY(128) conics; 84246c77f76be8cbcddccc1ae0058d589cbbdb468f7joshualitt IntArray qSubdivs; 84346c77f76be8cbcddccc1ae0058d589cbbdb468f7joshualitt FloatArray cWeights; 844351ba1b3218c436089805ebe8e72ad39020229f4joshualitt int quadCount = 0; 8457bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 8467bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt int instanceCount = fGeoData.count(); 8477bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt for (int i = 0; i < instanceCount; i++) { 8487bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt const Geometry& args = fGeoData[i]; 849351ba1b3218c436089805ebe8e72ad39020229f4joshualitt quadCount += gather_lines_and_quads(args.fPath, args.fViewMatrix, args.fDevClipBounds, 850351ba1b3218c436089805ebe8e72ad39020229f4joshualitt &lines, &quads, &conics, &qSubdivs, &cWeights); 851658d55cd6121c67488aaf5d0832c9712737f26a5joshualitt } 852658d55cd6121c67488aaf5d0832c9712737f26a5joshualitt 8537bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt int lineCount = lines.count() / 2; 8547bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt int conicCount = conics.count() / 3; 8557bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 85646c77f76be8cbcddccc1ae0058d589cbbdb468f7joshualitt // do lines first 8577bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt if (lineCount) { 858ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon SkAutoTUnref<const GrIndexBuffer> linesIndexBuffer( 859ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon ref_lines_index_buffer(batchTarget->resourceProvider())); 8607bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt batchTarget->initDraw(lineGP, pipeline); 8617bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 8627bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt // TODO remove this when batch is everywhere 8637bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt GrPipelineInfo init; 8647bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt init.fColorIgnored = fBatch.fColorIgnored; 8657bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt init.fOverrideColor = GrColor_ILLEGAL; 8667bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt init.fCoverageIgnored = fBatch.fCoverageIgnored; 8677bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt init.fUsesLocalCoords = this->usesLocalCoords(); 8687bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt lineGP->initBatchTracker(batchTarget->currentBatchTracker(), init); 8697bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 8707bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt const GrVertexBuffer* vertexBuffer; 8717bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt int firstVertex; 8727bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 8737bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt size_t vertexStride = lineGP->getVertexStride(); 8747bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt int vertexCount = kLineSegNumVertices * lineCount; 875e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon LineVertex* verts = reinterpret_cast<LineVertex*>( 876e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon batchTarget->makeVertSpace(vertexStride, vertexCount, &vertexBuffer, &firstVertex)); 8777bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 878e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon if (!verts|| !linesIndexBuffer) { 8794b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt SkDebugf("Could not allocate vertices\n"); 8804b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt return; 8814b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt } 8824b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt 8837bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt SkASSERT(lineGP->getVertexStride() == sizeof(LineVertex)); 8847bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 8857bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt for (int i = 0; i < lineCount; ++i) { 8867bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt add_line(&lines[2*i], toSrc, this->coverage(), &verts); 887eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com } 888aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 889681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com { 890e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon GrVertices vertices; 891e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon vertices.initInstanced(kTriangles_GrPrimitiveType, vertexBuffer, linesIndexBuffer, 892e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon firstVertex, kLineSegNumVertices, kIdxsPerLineSeg, lineCount, 893e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon kLineSegsNumInIdxBuffer); 894e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon batchTarget->draw(vertices); 8955383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 8965383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 8977475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com 8987bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt if (quadCount || conicCount) { 8997bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt const GrVertexBuffer* vertexBuffer; 9007bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt int firstVertex; 9017bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 902ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon SkAutoTUnref<const GrIndexBuffer> quadsIndexBuffer( 903ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon ref_quads_index_buffer(batchTarget->resourceProvider())); 904ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon 9057bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt size_t vertexStride = sizeof(BezierVertex); 9067bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt int vertexCount = kQuadNumVertices * quadCount + kQuadNumVertices * conicCount; 907e40d39725908d99d255496025411e5c9ca32663erobertphillips void *vertices = batchTarget->makeVertSpace(vertexStride, vertexCount, 908e40d39725908d99d255496025411e5c9ca32663erobertphillips &vertexBuffer, &firstVertex); 9097bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 910ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon if (!vertices || !quadsIndexBuffer) { 9114b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt SkDebugf("Could not allocate vertices\n"); 9124b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt return; 9134b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt } 9144b31de8328bbf3ee789157ae1dc6fe7cc74c796ajoshualitt 9157bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt // Setup vertices 9167bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt BezierVertex* verts = reinterpret_cast<BezierVertex*>(vertices); 9177bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 9187bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt int unsubdivQuadCnt = quads.count() / 3; 9197bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt for (int i = 0; i < unsubdivQuadCnt; ++i) { 9207bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt SkASSERT(qSubdivs[i] >= 0); 9217bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts); 922681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com } 9237475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com 9247bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt // Start Conics 9257bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt for (int i = 0; i < conicCount; ++i) { 9267bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &verts); 927681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com } 9287475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com 9297bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt if (quadCount > 0) { 9307bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt batchTarget->initDraw(quadGP, pipeline); 9317bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 9327bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt // TODO remove this when batch is everywhere 9337bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt GrPipelineInfo init; 9347bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt init.fColorIgnored = fBatch.fColorIgnored; 9357bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt init.fOverrideColor = GrColor_ILLEGAL; 9367bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt init.fCoverageIgnored = fBatch.fCoverageIgnored; 9377bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt init.fUsesLocalCoords = this->usesLocalCoords(); 9387bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt quadGP->initBatchTracker(batchTarget->currentBatchTracker(), init); 9397bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 9407bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt { 941e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon GrVertices verts; 942e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon verts.initInstanced(kTriangles_GrPrimitiveType, vertexBuffer, quadsIndexBuffer, 943e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon firstVertex, kQuadNumVertices, kIdxsPerQuad, quadCount, 944e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon kQuadsNumInIdxBuffer); 945e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon batchTarget->draw(verts); 946e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon firstVertex += quadCount * kQuadNumVertices; 9477bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt } 9487bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt } 9497bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 9507bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt if (conicCount > 0) { 9517bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt batchTarget->initDraw(conicGP, pipeline); 9527bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 9537bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt // TODO remove this when batch is everywhere 9547bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt GrPipelineInfo init; 9557bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt init.fColorIgnored = fBatch.fColorIgnored; 9567bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt init.fOverrideColor = GrColor_ILLEGAL; 9577bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt init.fCoverageIgnored = fBatch.fCoverageIgnored; 9587bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt init.fUsesLocalCoords = this->usesLocalCoords(); 9597bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt conicGP->initBatchTracker(batchTarget->currentBatchTracker(), init); 9607bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 9617bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt { 962e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon GrVertices verts; 963e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon verts.initInstanced(kTriangles_GrPrimitiveType, vertexBuffer, quadsIndexBuffer, 964e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon firstVertex, kQuadNumVertices, kIdxsPerQuad, conicCount, 965e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon kQuadsNumInIdxBuffer); 966e64eb570a5b9480bc24d0656ccabcff1ab13a229bsalomon batchTarget->draw(verts); 967681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com } 9685383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 969aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 9707bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt} 9717bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt 97240ded3241894076237844325c015fcc724e9d443joshualittstatic GrBatch* create_hairline_batch(GrColor color, 97340ded3241894076237844325c015fcc724e9d443joshualitt const SkMatrix& viewMatrix, 97440ded3241894076237844325c015fcc724e9d443joshualitt const SkPath& path, 97540ded3241894076237844325c015fcc724e9d443joshualitt const GrStrokeInfo& stroke, 976ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon const SkIRect& devClipBounds) { 97740ded3241894076237844325c015fcc724e9d443joshualitt SkScalar hairlineCoverage; 97840ded3241894076237844325c015fcc724e9d443joshualitt uint8_t newCoverage = 0xff; 97940ded3241894076237844325c015fcc724e9d443joshualitt if (GrPathRenderer::IsStrokeHairlineOrEquivalent(stroke, viewMatrix, &hairlineCoverage)) { 98040ded3241894076237844325c015fcc724e9d443joshualitt newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff); 98140ded3241894076237844325c015fcc724e9d443joshualitt } 98240ded3241894076237844325c015fcc724e9d443joshualitt 98340ded3241894076237844325c015fcc724e9d443joshualitt AAHairlineBatch::Geometry geometry; 98440ded3241894076237844325c015fcc724e9d443joshualitt geometry.fColor = color; 98540ded3241894076237844325c015fcc724e9d443joshualitt geometry.fCoverage = newCoverage; 98640ded3241894076237844325c015fcc724e9d443joshualitt geometry.fViewMatrix = viewMatrix; 98740ded3241894076237844325c015fcc724e9d443joshualitt geometry.fPath = path; 98840ded3241894076237844325c015fcc724e9d443joshualitt geometry.fDevClipBounds = devClipBounds; 98940ded3241894076237844325c015fcc724e9d443joshualitt 990ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon return AAHairlineBatch::Create(geometry); 99140ded3241894076237844325c015fcc724e9d443joshualitt} 99240ded3241894076237844325c015fcc724e9d443joshualitt 9937bc18b75ee473cd90c5577270e378f99cedd4ab9joshualittbool GrAAHairLinePathRenderer::onDrawPath(GrDrawTarget* target, 9947bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt GrPipelineBuilder* pipelineBuilder, 9957bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt GrColor color, 9967bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt const SkMatrix& viewMatrix, 9977bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt const SkPath& path, 9981899651ffc459f5462aa989cd6d08507947b67e4kkinnunen const GrStrokeInfo& stroke, 9997bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt bool) { 10007bc18b75ee473cd90c5577270e378f99cedd4ab9joshualitt SkIRect devClipBounds; 100144701df5ce572ac3cccec785cf52103d3d5d14a5joshualitt pipelineBuilder->clip().getConservativeBounds(pipelineBuilder->getRenderTarget(), 100244701df5ce572ac3cccec785cf52103d3d5d14a5joshualitt &devClipBounds); 10037475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com 100440ded3241894076237844325c015fcc724e9d443joshualitt SkAutoTUnref<GrBatch> batch(create_hairline_batch(color, viewMatrix, path, stroke, 1005ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon devClipBounds)); 100699c7c07e0f1f7b78980eb21d84bebda8b45a7178joshualitt target->drawBatch(pipelineBuilder, batch); 10074647f9059825c062169d4d454c12640d82ae16c0bsalomon@google.com 1008c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com return true; 1009aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 101040ded3241894076237844325c015fcc724e9d443joshualitt 101140ded3241894076237844325c015fcc724e9d443joshualitt/////////////////////////////////////////////////////////////////////////////////////////////////// 101240ded3241894076237844325c015fcc724e9d443joshualitt 101340ded3241894076237844325c015fcc724e9d443joshualitt#ifdef GR_TEST_UTILS 101440ded3241894076237844325c015fcc724e9d443joshualitt 101540ded3241894076237844325c015fcc724e9d443joshualittBATCH_TEST_DEFINE(AAHairlineBatch) { 101640ded3241894076237844325c015fcc724e9d443joshualitt GrColor color = GrRandomColor(random); 101740ded3241894076237844325c015fcc724e9d443joshualitt SkMatrix viewMatrix = GrTest::TestMatrix(random); 101840ded3241894076237844325c015fcc724e9d443joshualitt GrStrokeInfo stroke(SkStrokeRec::kHairline_InitStyle); 101940ded3241894076237844325c015fcc724e9d443joshualitt SkPath path = GrTest::TestPath(random); 102040ded3241894076237844325c015fcc724e9d443joshualitt SkIRect devClipBounds; 102140ded3241894076237844325c015fcc724e9d443joshualitt devClipBounds.setEmpty(); 1022ed0bcad9c8147fd37c23bdda00ec27ec9ef8d66bbsalomon return create_hairline_batch(color, viewMatrix, path, stroke, devClipBounds); 102340ded3241894076237844325c015fcc724e9d443joshualitt} 102440ded3241894076237844325c015fcc724e9d443joshualitt 102540ded3241894076237844325c015fcc724e9d443joshualitt#endif 1026