Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(44)

Side by Side Diff: src/gpu/GrDefaultPathRenderer.cpp

Issue 1311673014: Remove GrAddPathRenderers_default (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: tweaks Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/gpu/GrDefaultPathRenderer.h ('k') | src/gpu/GrPathRenderer.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "GrDefaultPathRenderer.h"
9
10 #include "GrBatchFlushState.h"
11 #include "GrBatchTest.h"
12 #include "GrContext.h"
13 #include "GrDefaultGeoProcFactory.h"
14 #include "GrPathUtils.h"
15 #include "GrPipelineBuilder.h"
16 #include "GrVertices.h"
17 #include "SkGeometry.h"
18 #include "SkString.h"
19 #include "SkStrokeRec.h"
20 #include "SkTLazy.h"
21 #include "SkTraceEvent.h"
22
23 #include "batches/GrVertexBatch.h"
24
25 GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport,
26 bool stencilWrapOpsSupport)
27 : fSeparateStencil(separateStencilSupport)
28 , fStencilWrapOps(stencilWrapOpsSupport) {
29 }
30
31
32 ////////////////////////////////////////////////////////////////////////////////
33 // Stencil rules for paths
34
35 ////// Even/Odd
36
37 GR_STATIC_CONST_SAME_STENCIL(gEOStencilPass,
38 kInvert_StencilOp,
39 kKeep_StencilOp,
40 kAlwaysIfInClip_StencilFunc,
41 0xffff,
42 0xffff,
43 0xffff);
44
45 // ok not to check clip b/c stencil pass only wrote inside clip
46 GR_STATIC_CONST_SAME_STENCIL(gEOColorPass,
47 kZero_StencilOp,
48 kZero_StencilOp,
49 kNotEqual_StencilFunc,
50 0xffff,
51 0x0000,
52 0xffff);
53
54 // have to check clip b/c outside clip will always be zero.
55 GR_STATIC_CONST_SAME_STENCIL(gInvEOColorPass,
56 kZero_StencilOp,
57 kZero_StencilOp,
58 kEqualIfInClip_StencilFunc,
59 0xffff,
60 0x0000,
61 0xffff);
62
63 ////// Winding
64
65 // when we have separate stencil we increment front faces / decrement back faces
66 // when we don't have wrap incr and decr we use the stencil test to simulate
67 // them.
68
69 GR_STATIC_CONST_STENCIL(gWindStencilSeparateWithWrap,
70 kIncWrap_StencilOp, kDecWrap_StencilOp,
71 kKeep_StencilOp, kKeep_StencilOp,
72 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
73 0xffff, 0xffff,
74 0xffff, 0xffff,
75 0xffff, 0xffff);
76
77 // if inc'ing the max value, invert to make 0
78 // if dec'ing zero invert to make all ones.
79 // we can't avoid touching the stencil on both passing and
80 // failing, so we can't resctrict ourselves to the clip.
81 GR_STATIC_CONST_STENCIL(gWindStencilSeparateNoWrap,
82 kInvert_StencilOp, kInvert_StencilOp,
83 kIncClamp_StencilOp, kDecClamp_StencilOp,
84 kEqual_StencilFunc, kEqual_StencilFunc,
85 0xffff, 0xffff,
86 0xffff, 0x0000,
87 0xffff, 0xffff);
88
89 // When there are no separate faces we do two passes to setup the winding rule
90 // stencil. First we draw the front faces and inc, then we draw the back faces
91 // and dec. These are same as the above two split into the incrementing and
92 // decrementing passes.
93 GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapInc,
94 kIncWrap_StencilOp,
95 kKeep_StencilOp,
96 kAlwaysIfInClip_StencilFunc,
97 0xffff,
98 0xffff,
99 0xffff);
100
101 GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapDec,
102 kDecWrap_StencilOp,
103 kKeep_StencilOp,
104 kAlwaysIfInClip_StencilFunc,
105 0xffff,
106 0xffff,
107 0xffff);
108
109 GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapInc,
110 kInvert_StencilOp,
111 kIncClamp_StencilOp,
112 kEqual_StencilFunc,
113 0xffff,
114 0xffff,
115 0xffff);
116
117 GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapDec,
118 kInvert_StencilOp,
119 kDecClamp_StencilOp,
120 kEqual_StencilFunc,
121 0xffff,
122 0x0000,
123 0xffff);
124
125 // Color passes are the same whether we use the two-sided stencil or two passes
126
127 GR_STATIC_CONST_SAME_STENCIL(gWindColorPass,
128 kZero_StencilOp,
129 kZero_StencilOp,
130 kNonZeroIfInClip_StencilFunc,
131 0xffff,
132 0x0000,
133 0xffff);
134
135 GR_STATIC_CONST_SAME_STENCIL(gInvWindColorPass,
136 kZero_StencilOp,
137 kZero_StencilOp,
138 kEqualIfInClip_StencilFunc,
139 0xffff,
140 0x0000,
141 0xffff);
142
143 ////// Normal render to stencil
144
145 // Sometimes the default path renderer can draw a path directly to the stencil
146 // buffer without having to first resolve the interior / exterior.
147 GR_STATIC_CONST_SAME_STENCIL(gDirectToStencil,
148 kZero_StencilOp,
149 kIncClamp_StencilOp,
150 kAlwaysIfInClip_StencilFunc,
151 0xffff,
152 0x0000,
153 0xffff);
154
155 ////////////////////////////////////////////////////////////////////////////////
156 // Helpers for drawPath
157
158 #define STENCIL_OFF 0 // Always disable stencil (even when needed)
159
160 static inline bool single_pass_path(const SkPath& path, const SkStrokeRec& strok e) {
161 #if STENCIL_OFF
162 return true;
163 #else
164 if (!stroke.isHairlineStyle() && !path.isInverseFillType()) {
165 return path.isConvex();
166 }
167 return false;
168 #endif
169 }
170
171 GrPathRenderer::StencilSupport
172 GrDefaultPathRenderer::onGetStencilSupport(const SkPath& path, const GrStrokeInf o& stroke) const {
173 if (single_pass_path(path, stroke)) {
174 return GrPathRenderer::kNoRestriction_StencilSupport;
175 } else {
176 return GrPathRenderer::kStencilOnly_StencilSupport;
177 }
178 }
179
180 static inline void append_countour_edge_indices(bool hairLine,
181 uint16_t fanCenterIdx,
182 uint16_t edgeV0Idx,
183 uint16_t** indices) {
184 // when drawing lines we're appending line segments along
185 // the contour. When applying the other fill rules we're
186 // drawing triangle fans around fanCenterIdx.
187 if (!hairLine) {
188 *((*indices)++) = fanCenterIdx;
189 }
190 *((*indices)++) = edgeV0Idx;
191 *((*indices)++) = edgeV0Idx + 1;
192 }
193
194 static inline void add_quad(SkPoint** vert, const SkPoint* base, const SkPoint p ts[],
195 SkScalar srcSpaceTolSqd, SkScalar srcSpaceTol, bool indexed,
196 bool isHairline, uint16_t subpathIdxStart, int offse t, uint16_t** idx) {
197 // first pt of quad is the pt we ended on in previous step
198 uint16_t firstQPtIdx = (uint16_t)(*vert - base) - 1 + offset;
199 uint16_t numPts = (uint16_t)
200 GrPathUtils::generateQuadraticPoints(
201 pts[0], pts[1], pts[2],
202 srcSpaceTolSqd, vert,
203 GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
204 if (indexed) {
205 for (uint16_t i = 0; i < numPts; ++i) {
206 append_countour_edge_indices(isHairline, subpathIdxStart,
207 firstQPtIdx + i, idx);
208 }
209 }
210 }
211
212 class DefaultPathBatch : public GrVertexBatch {
213 public:
214 struct Geometry {
215 GrColor fColor;
216 SkPath fPath;
217 SkScalar fTolerance;
218 };
219
220 static GrDrawBatch* Create(const Geometry& geometry, uint8_t coverage,
221 const SkMatrix& viewMatrix, bool isHairline,
222 const SkRect& devBounds) {
223 return new DefaultPathBatch(geometry, coverage, viewMatrix, isHairline, devBounds);
224 }
225
226 const char* name() const override { return "DefaultPathBatch"; }
227
228 void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
229 // When this is called on a batch, there is only one geometry bundle
230 out->setKnownFourComponents(fGeoData[0].fColor);
231 }
232 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
233 out->setKnownSingleComponent(this->coverage());
234 }
235
236 private:
237 void initBatchTracker(const GrPipelineOptimizations& opt) override {
238 // Handle any color overrides
239 if (!opt.readsColor()) {
240 fGeoData[0].fColor = GrColor_ILLEGAL;
241 }
242 opt.getOverrideColorIfSet(&fGeoData[0].fColor);
243
244 // setup batch properties
245 fBatch.fColorIgnored = !opt.readsColor();
246 fBatch.fColor = fGeoData[0].fColor;
247 fBatch.fUsesLocalCoords = opt.readsLocalCoords();
248 fBatch.fCoverageIgnored = !opt.readsCoverage();
249 }
250
251 void onPrepareDraws(Target* target) override {
252 SkAutoTUnref<const GrGeometryProcessor> gp;
253 {
254 using namespace GrDefaultGeoProcFactory;
255 Color color(this->color());
256 Coverage coverage(this->coverage());
257 if (this->coverageIgnored()) {
258 coverage.fType = Coverage::kNone_Type;
259 }
260 LocalCoords localCoords(this->usesLocalCoords() ? LocalCoords::kUseP osition_Type :
261 LocalCoords::kUnus ed_Type);
262 gp.reset(GrDefaultGeoProcFactory::Create(color, coverage, localCoord s,
263 this->viewMatrix()));
264 }
265
266 size_t vertexStride = gp->getVertexStride();
267 SkASSERT(vertexStride == sizeof(SkPoint));
268
269 target->initDraw(gp, this->pipeline());
270
271 int instanceCount = fGeoData.count();
272
273 // compute number of vertices
274 int maxVertices = 0;
275
276 // We will use index buffers if we have multiple paths or one path with multiple contours
277 bool isIndexed = instanceCount > 1;
278 for (int i = 0; i < instanceCount; i++) {
279 Geometry& args = fGeoData[i];
280
281 int contourCount;
282 maxVertices += GrPathUtils::worstCasePointCount(args.fPath, &contour Count,
283 args.fTolerance);
284
285 isIndexed = isIndexed || contourCount > 1;
286 }
287
288 if (maxVertices == 0 || maxVertices > ((int)SK_MaxU16 + 1)) {
289 SkDebugf("Cannot render path (%d)\n", maxVertices);
290 return;
291 }
292
293 // determine primitiveType
294 int maxIndices = 0;
295 GrPrimitiveType primitiveType;
296 if (this->isHairline()) {
297 if (isIndexed) {
298 maxIndices = 2 * maxVertices;
299 primitiveType = kLines_GrPrimitiveType;
300 } else {
301 primitiveType = kLineStrip_GrPrimitiveType;
302 }
303 } else {
304 if (isIndexed) {
305 maxIndices = 3 * maxVertices;
306 primitiveType = kTriangles_GrPrimitiveType;
307 } else {
308 primitiveType = kTriangleFan_GrPrimitiveType;
309 }
310 }
311
312 // allocate vertex / index buffers
313 const GrVertexBuffer* vertexBuffer;
314 int firstVertex;
315
316 void* verts = target->makeVertexSpace(vertexStride, maxVertices,
317 &vertexBuffer, &firstVertex);
318
319 if (!verts) {
320 SkDebugf("Could not allocate vertices\n");
321 return;
322 }
323
324 const GrIndexBuffer* indexBuffer = nullptr;
325 int firstIndex = 0;
326
327 void* indices = nullptr;
328 if (isIndexed) {
329 indices = target->makeIndexSpace(maxIndices, &indexBuffer, &firstInd ex);
330
331 if (!indices) {
332 SkDebugf("Could not allocate indices\n");
333 return;
334 }
335 }
336
337 // fill buffers
338 int vertexOffset = 0;
339 int indexOffset = 0;
340 for (int i = 0; i < instanceCount; i++) {
341 Geometry& args = fGeoData[i];
342
343 int vertexCnt = 0;
344 int indexCnt = 0;
345 if (!this->createGeom(verts,
346 vertexOffset,
347 indices,
348 indexOffset,
349 &vertexCnt,
350 &indexCnt,
351 args.fPath,
352 args.fTolerance,
353 isIndexed)) {
354 return;
355 }
356
357 vertexOffset += vertexCnt;
358 indexOffset += indexCnt;
359 SkASSERT(vertexOffset <= maxVertices && indexOffset <= maxIndices);
360 }
361
362 GrVertices vertices;
363 if (isIndexed) {
364 vertices.initIndexed(primitiveType, vertexBuffer, indexBuffer, first Vertex, firstIndex,
365 vertexOffset, indexOffset);
366 } else {
367 vertices.init(primitiveType, vertexBuffer, firstVertex, vertexOffset );
368 }
369 target->draw(vertices);
370
371 // put back reserves
372 target->putBackIndices((size_t)(maxIndices - indexOffset));
373 target->putBackVertices((size_t)(maxVertices - vertexOffset), (size_t)ve rtexStride);
374 }
375
376 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
377
378 DefaultPathBatch(const Geometry& geometry, uint8_t coverage, const SkMatrix& viewMatrix,
379 bool isHairline, const SkRect& devBounds) {
380 this->initClassID<DefaultPathBatch>();
381 fBatch.fCoverage = coverage;
382 fBatch.fIsHairline = isHairline;
383 fBatch.fViewMatrix = viewMatrix;
384 fGeoData.push_back(geometry);
385
386 this->setBounds(devBounds);
387 }
388
389 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
390 DefaultPathBatch* that = t->cast<DefaultPathBatch>();
391 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pi peline(),
392 that->bounds(), caps)) {
393 return false;
394 }
395
396 if (this->color() != that->color()) {
397 return false;
398 }
399
400 if (this->coverage() != that->coverage()) {
401 return false;
402 }
403
404 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
405 return false;
406 }
407
408 if (this->isHairline() != that->isHairline()) {
409 return false;
410 }
411
412 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin()) ;
413 this->joinBounds(that->bounds());
414 return true;
415 }
416
417 bool createGeom(void* vertices,
418 size_t vertexOffset,
419 void* indices,
420 size_t indexOffset,
421 int* vertexCnt,
422 int* indexCnt,
423 const SkPath& path,
424 SkScalar srcSpaceTol,
425 bool isIndexed) {
426 {
427 SkScalar srcSpaceTolSqd = SkScalarMul(srcSpaceTol, srcSpaceTol);
428
429 uint16_t indexOffsetU16 = (uint16_t)indexOffset;
430 uint16_t vertexOffsetU16 = (uint16_t)vertexOffset;
431
432 uint16_t* idxBase = reinterpret_cast<uint16_t*>(indices) + indexOffs etU16;
433 uint16_t* idx = idxBase;
434 uint16_t subpathIdxStart = vertexOffsetU16;
435
436 SkPoint* base = reinterpret_cast<SkPoint*>(vertices) + vertexOffset;
437 SkPoint* vert = base;
438
439 SkPoint pts[4];
440
441 bool first = true;
442 int subpath = 0;
443
444 SkPath::Iter iter(path, false);
445
446 bool done = false;
447 while (!done) {
448 SkPath::Verb verb = iter.next(pts);
449 switch (verb) {
450 case SkPath::kMove_Verb:
451 if (!first) {
452 uint16_t currIdx = (uint16_t) (vert - base) + vertex OffsetU16;
453 subpathIdxStart = currIdx;
454 ++subpath;
455 }
456 *vert = pts[0];
457 vert++;
458 break;
459 case SkPath::kLine_Verb:
460 if (isIndexed) {
461 uint16_t prevIdx = (uint16_t)(vert - base) - 1 + ver texOffsetU16;
462 append_countour_edge_indices(this->isHairline(), sub pathIdxStart,
463 prevIdx, &idx);
464 }
465 *(vert++) = pts[1];
466 break;
467 case SkPath::kConic_Verb: {
468 SkScalar weight = iter.conicWeight();
469 SkAutoConicToQuads converter;
470 // Converting in src-space, hance the finer tolerance (0 .25)
471 // TODO: find a way to do this in dev-space so the toler ance means something
472 const SkPoint* quadPts = converter.computeQuads(pts, wei ght, 0.25f);
473 for (int i = 0; i < converter.countQuads(); ++i) {
474 add_quad(&vert, base, quadPts + i*2, srcSpaceTolSqd, srcSpaceTol,
475 isIndexed, this->isHairline(), subpathIdxSt art,
476 (int)vertexOffset, &idx);
477 }
478 break;
479 }
480 case SkPath::kQuad_Verb:
481 add_quad(&vert, base, pts, srcSpaceTolSqd, srcSpaceTol, isIndexed,
482 this->isHairline(), subpathIdxStart, (int)verte xOffset, &idx);
483 break;
484 case SkPath::kCubic_Verb: {
485 // first pt of cubic is the pt we ended on in previous s tep
486 uint16_t firstCPtIdx = (uint16_t)(vert - base) - 1 + ver texOffsetU16;
487 uint16_t numPts = (uint16_t) GrPathUtils::generateCubicP oints(
488 pts[0], pts[1], pts[2], pts[3],
489 srcSpaceTolSqd, &vert,
490 GrPathUtils::cubicPointCount(pts, srcSpa ceTol));
491 if (isIndexed) {
492 for (uint16_t i = 0; i < numPts; ++i) {
493 append_countour_edge_indices(this->isHairline(), subpathIdxStart,
494 firstCPtIdx + i, &i dx);
495 }
496 }
497 break;
498 }
499 case SkPath::kClose_Verb:
500 break;
501 case SkPath::kDone_Verb:
502 done = true;
503 }
504 first = false;
505 }
506
507 *vertexCnt = static_cast<int>(vert - base);
508 *indexCnt = static_cast<int>(idx - idxBase);
509
510 }
511 return true;
512 }
513
514 GrColor color() const { return fBatch.fColor; }
515 uint8_t coverage() const { return fBatch.fCoverage; }
516 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
517 const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; }
518 bool isHairline() const { return fBatch.fIsHairline; }
519 bool coverageIgnored() const { return fBatch.fCoverageIgnored; }
520
521 struct BatchTracker {
522 GrColor fColor;
523 uint8_t fCoverage;
524 SkMatrix fViewMatrix;
525 bool fUsesLocalCoords;
526 bool fColorIgnored;
527 bool fCoverageIgnored;
528 bool fIsHairline;
529 };
530
531 BatchTracker fBatch;
532 SkSTArray<1, Geometry, true> fGeoData;
533 };
534
535 bool GrDefaultPathRenderer::internalDrawPath(GrDrawTarget* target,
536 GrPipelineBuilder* pipelineBuilder,
537 GrColor color,
538 const SkMatrix& viewMatrix,
539 const SkPath& path,
540 const GrStrokeInfo& origStroke,
541 bool stencilOnly) {
542 SkTCopyOnFirstWrite<GrStrokeInfo> stroke(origStroke);
543
544 SkScalar hairlineCoverage;
545 uint8_t newCoverage = 0xff;
546 if (IsStrokeHairlineOrEquivalent(*stroke, viewMatrix, &hairlineCoverage)) {
547 newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff);
548
549 if (!stroke->isHairlineStyle()) {
550 stroke.writable()->setHairlineStyle();
551 }
552 }
553
554 const bool isHairline = stroke->isHairlineStyle();
555
556 // Save the current xp on the draw state so we can reset it if needed
557 SkAutoTUnref<const GrXPFactory> backupXPFactory(SkRef(pipelineBuilder->getXP Factory()));
558 // face culling doesn't make sense here
559 SkASSERT(GrPipelineBuilder::kBoth_DrawFace == pipelineBuilder->getDrawFace() );
560
561 int passCount = 0;
562 const GrStencilSettings* passes[3];
563 GrPipelineBuilder::DrawFace drawFace[3];
564 bool reverse = false;
565 bool lastPassIsBounds;
566
567 if (isHairline) {
568 passCount = 1;
569 if (stencilOnly) {
570 passes[0] = &gDirectToStencil;
571 } else {
572 passes[0] = nullptr;
573 }
574 lastPassIsBounds = false;
575 drawFace[0] = GrPipelineBuilder::kBoth_DrawFace;
576 } else {
577 if (single_pass_path(path, *stroke)) {
578 passCount = 1;
579 if (stencilOnly) {
580 passes[0] = &gDirectToStencil;
581 } else {
582 passes[0] = nullptr;
583 }
584 drawFace[0] = GrPipelineBuilder::kBoth_DrawFace;
585 lastPassIsBounds = false;
586 } else {
587 switch (path.getFillType()) {
588 case SkPath::kInverseEvenOdd_FillType:
589 reverse = true;
590 // fallthrough
591 case SkPath::kEvenOdd_FillType:
592 passes[0] = &gEOStencilPass;
593 if (stencilOnly) {
594 passCount = 1;
595 lastPassIsBounds = false;
596 } else {
597 passCount = 2;
598 lastPassIsBounds = true;
599 if (reverse) {
600 passes[1] = &gInvEOColorPass;
601 } else {
602 passes[1] = &gEOColorPass;
603 }
604 }
605 drawFace[0] = drawFace[1] = GrPipelineBuilder::kBoth_DrawFac e;
606 break;
607
608 case SkPath::kInverseWinding_FillType:
609 reverse = true;
610 // fallthrough
611 case SkPath::kWinding_FillType:
612 if (fSeparateStencil) {
613 if (fStencilWrapOps) {
614 passes[0] = &gWindStencilSeparateWithWrap;
615 } else {
616 passes[0] = &gWindStencilSeparateNoWrap;
617 }
618 passCount = 2;
619 drawFace[0] = GrPipelineBuilder::kBoth_DrawFace;
620 } else {
621 if (fStencilWrapOps) {
622 passes[0] = &gWindSingleStencilWithWrapInc;
623 passes[1] = &gWindSingleStencilWithWrapDec;
624 } else {
625 passes[0] = &gWindSingleStencilNoWrapInc;
626 passes[1] = &gWindSingleStencilNoWrapDec;
627 }
628 // which is cw and which is ccw is arbitrary.
629 drawFace[0] = GrPipelineBuilder::kCW_DrawFace;
630 drawFace[1] = GrPipelineBuilder::kCCW_DrawFace;
631 passCount = 3;
632 }
633 if (stencilOnly) {
634 lastPassIsBounds = false;
635 --passCount;
636 } else {
637 lastPassIsBounds = true;
638 drawFace[passCount-1] = GrPipelineBuilder::kBoth_DrawFac e;
639 if (reverse) {
640 passes[passCount-1] = &gInvWindColorPass;
641 } else {
642 passes[passCount-1] = &gWindColorPass;
643 }
644 }
645 break;
646 default:
647 SkDEBUGFAIL("Unknown path fFill!");
648 return false;
649 }
650 }
651 }
652
653 SkScalar tol = GrPathUtils::kDefaultTolerance;
654 SkScalar srcSpaceTol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, pat h.getBounds());
655
656 SkRect devBounds;
657 GetPathDevBounds(path, pipelineBuilder->getRenderTarget(), viewMatrix, &devB ounds);
658
659 for (int p = 0; p < passCount; ++p) {
660 pipelineBuilder->setDrawFace(drawFace[p]);
661 if (passes[p]) {
662 *pipelineBuilder->stencil() = *passes[p];
663 }
664
665 if (lastPassIsBounds && (p == passCount-1)) {
666 // Reset the XP Factory on pipelineBuilder
667 pipelineBuilder->setXPFactory(backupXPFactory);
668 SkRect bounds;
669 SkMatrix localMatrix = SkMatrix::I();
670 if (reverse) {
671 SkASSERT(pipelineBuilder->getRenderTarget());
672 // draw over the dev bounds (which will be the whole dst surface for inv fill).
673 bounds = devBounds;
674 SkMatrix vmi;
675 // mapRect through persp matrix may not be correct
676 if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) {
677 vmi.mapRect(&bounds);
678 } else {
679 if (!viewMatrix.invert(&localMatrix)) {
680 return false;
681 }
682 }
683 } else {
684 bounds = path.getBounds();
685 }
686 const SkMatrix& viewM = (reverse && viewMatrix.hasPerspective()) ? S kMatrix::I() :
687 v iewMatrix;
688 target->drawNonAARect(*pipelineBuilder, color, viewM, bounds, localM atrix);
689 } else {
690 if (passCount > 1) {
691 pipelineBuilder->setDisableColorXPFactory();
692 }
693
694 DefaultPathBatch::Geometry geometry;
695 geometry.fColor = color;
696 geometry.fPath = path;
697 geometry.fTolerance = srcSpaceTol;
698
699 SkAutoTUnref<GrDrawBatch> batch(DefaultPathBatch::Create(geometry, n ewCoverage,
700 viewMatrix, isHairline,
701 devBounds)) ;
702
703 target->drawBatch(*pipelineBuilder, batch);
704 }
705 }
706 return true;
707 }
708
709 bool GrDefaultPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
710 // this class can draw any path with any fill but doesn't do any anti-aliasi ng.
711 return !args.fAntiAlias && (args.fStroke->isFillStyle() ||
712 IsStrokeHairlineOrEquivalent(*args.fStroke, *arg s.fViewMatrix,
713 nullptr));
714 }
715
716 bool GrDefaultPathRenderer::onDrawPath(const DrawPathArgs& args) {
717 return this->internalDrawPath(args.fTarget,
718 args.fPipelineBuilder,
719 args.fColor,
720 *args.fViewMatrix,
721 *args.fPath,
722 *args.fStroke,
723 false);
724 }
725
726 void GrDefaultPathRenderer::onStencilPath(const StencilPathArgs& args) {
727 SkASSERT(SkPath::kInverseEvenOdd_FillType != args.fPath->getFillType());
728 SkASSERT(SkPath::kInverseWinding_FillType != args.fPath->getFillType());
729 this->internalDrawPath(args.fTarget, args.fPipelineBuilder, GrColor_WHITE, * args.fViewMatrix,
730 *args.fPath, *args.fStroke, true);
731 }
732
733 //////////////////////////////////////////////////////////////////////////////// ///////////////////
734
735 #ifdef GR_TEST_UTILS
736
737 DRAW_BATCH_TEST_DEFINE(DefaultPathBatch) {
738 GrColor color = GrRandomColor(random);
739 SkMatrix viewMatrix = GrTest::TestMatrix(random);
740
741 // For now just hairlines because the other types of draws require two batch es.
742 // TODO we should figure out a way to combine the stencil and cover steps in to one batch
743 GrStrokeInfo stroke(SkStrokeRec::kHairline_InitStyle);
744 SkPath path = GrTest::TestPath(random);
745
746 // Compute srcSpaceTol
747 SkRect bounds = path.getBounds();
748 SkScalar tol = GrPathUtils::kDefaultTolerance;
749 SkScalar srcSpaceTol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, bou nds);
750
751 DefaultPathBatch::Geometry geometry;
752 geometry.fColor = color;
753 geometry.fPath = path;
754 geometry.fTolerance = srcSpaceTol;
755
756 viewMatrix.mapRect(&bounds);
757 uint8_t coverage = GrRandomCoverage(random);
758 return DefaultPathBatch::Create(geometry, coverage, viewMatrix, true, bounds );
759 }
760
761 #endif
OLDNEW
« no previous file with comments | « src/gpu/GrDefaultPathRenderer.h ('k') | src/gpu/GrPathRenderer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698