1 
2 /*
3  * Copyright 2012 Google Inc.
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 
9 
10 #include "GrStencilAndCoverPathRenderer.h"
11 #include "GrCaps.h"
12 #include "GrContext.h"
13 #include "GrDrawPathBatch.h"
14 #include "GrGpu.h"
15 #include "GrPath.h"
16 #include "GrRenderTarget.h"
17 #include "GrResourceProvider.h"
18 #include "GrStrokeInfo.h"
19 #include "batches/GrRectBatchFactory.h"
20 
Create(GrResourceProvider * resourceProvider,const GrCaps & caps)21 GrPathRenderer* GrStencilAndCoverPathRenderer::Create(GrResourceProvider* resourceProvider,
22                                                       const GrCaps& caps) {
23     if (caps.shaderCaps()->pathRenderingSupport()) {
24         return new GrStencilAndCoverPathRenderer(resourceProvider);
25     } else {
26         return nullptr;
27     }
28 }
29 
GrStencilAndCoverPathRenderer(GrResourceProvider * resourceProvider)30 GrStencilAndCoverPathRenderer::GrStencilAndCoverPathRenderer(GrResourceProvider* resourceProvider)
31     : fResourceProvider(resourceProvider) {
32 }
33 
onCanDrawPath(const CanDrawPathArgs & args) const34 bool GrStencilAndCoverPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
35     if (args.fStroke->isHairlineStyle()) {
36         return false;
37     }
38     if (!args.fIsStencilDisabled) {
39         return false;
40     }
41     if (args.fAntiAlias) {
42         return args.fIsStencilBufferMSAA;
43     } else {
44         return true; // doesn't do per-path AA, relies on the target having MSAA
45     }
46 }
47 
get_gr_path(GrResourceProvider * resourceProvider,const SkPath & skPath,const GrStrokeInfo & stroke)48 static GrPath* get_gr_path(GrResourceProvider* resourceProvider, const SkPath& skPath,
49                            const GrStrokeInfo& stroke) {
50     GrUniqueKey key;
51     bool isVolatile;
52     GrPath::ComputeKey(skPath, stroke, &key, &isVolatile);
53     SkAutoTUnref<GrPath> path(
54         static_cast<GrPath*>(resourceProvider->findAndRefResourceByUniqueKey(key)));
55     if (!path) {
56         path.reset(resourceProvider->createPath(skPath, stroke));
57         if (!isVolatile) {
58             resourceProvider->assignUniqueKeyToResource(key, path);
59         }
60     } else {
61         SkASSERT(path->isEqualTo(skPath, stroke));
62     }
63     return path.detach();
64 }
65 
onStencilPath(const StencilPathArgs & args)66 void GrStencilAndCoverPathRenderer::onStencilPath(const StencilPathArgs& args) {
67     GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(),
68                               "GrStencilAndCoverPathRenderer::onStencilPath");
69     SkASSERT(!args.fPath->isInverseFillType());
70     SkAutoTUnref<GrPath> p(get_gr_path(fResourceProvider, *args.fPath, *args.fStroke));
71     args.fTarget->stencilPath(*args.fPipelineBuilder, *args.fViewMatrix, p, p->getFillType());
72 }
73 
onDrawPath(const DrawPathArgs & args)74 bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) {
75     GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(),
76                               "GrStencilAndCoverPathRenderer::onDrawPath");
77     SkASSERT(!args.fStroke->isHairlineStyle());
78     const SkPath& path = *args.fPath;
79     GrPipelineBuilder* pipelineBuilder = args.fPipelineBuilder;
80     const SkMatrix& viewMatrix = *args.fViewMatrix;
81 
82     SkASSERT(pipelineBuilder->getStencil().isDisabled());
83 
84     if (args.fAntiAlias) {
85         SkASSERT(pipelineBuilder->getRenderTarget()->isStencilBufferMultisampled());
86         pipelineBuilder->enableState(GrPipelineBuilder::kHWAntialias_Flag);
87     }
88 
89     SkAutoTUnref<GrPath> p(get_gr_path(fResourceProvider, path, *args.fStroke));
90 
91     if (path.isInverseFillType()) {
92         GR_STATIC_CONST_SAME_STENCIL(kInvertedStencilPass,
93             kKeep_StencilOp,
94             kZero_StencilOp,
95             // We know our rect will hit pixels outside the clip and the user bits will be 0
96             // outside the clip. So we can't just fill where the user bits are 0. We also need to
97             // check that the clip bit is set.
98             kEqualIfInClip_StencilFunc,
99             0xffff,
100             0x0000,
101             0xffff);
102 
103         pipelineBuilder->setStencil(kInvertedStencilPass);
104 
105         // fake inverse with a stencil and cover
106         args.fTarget->stencilPath(*pipelineBuilder, viewMatrix, p, p->getFillType());
107 
108         SkMatrix invert = SkMatrix::I();
109         SkRect bounds =
110             SkRect::MakeLTRB(0, 0, SkIntToScalar(pipelineBuilder->getRenderTarget()->width()),
111                              SkIntToScalar(pipelineBuilder->getRenderTarget()->height()));
112         SkMatrix vmi;
113         // mapRect through persp matrix may not be correct
114         if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) {
115             vmi.mapRect(&bounds);
116             // theoretically could set bloat = 0, instead leave it because of matrix inversion
117             // precision.
118             SkScalar bloat = viewMatrix.getMaxScale() * SK_ScalarHalf;
119             bounds.outset(bloat, bloat);
120         } else {
121             if (!viewMatrix.invert(&invert)) {
122                 return false;
123             }
124         }
125         const SkMatrix& viewM = viewMatrix.hasPerspective() ? SkMatrix::I() : viewMatrix;
126         if (pipelineBuilder->getRenderTarget()->hasMixedSamples()) {
127             pipelineBuilder->disableState(GrPipelineBuilder::kHWAntialias_Flag);
128         }
129 
130         SkAutoTUnref<GrDrawBatch> batch(
131                 GrRectBatchFactory::CreateNonAAFill(args.fColor, viewM, bounds, nullptr,
132                                                     &invert));
133         args.fTarget->drawBatch(*pipelineBuilder, batch);
134     } else {
135         GR_STATIC_CONST_SAME_STENCIL(kStencilPass,
136             kZero_StencilOp,
137             kKeep_StencilOp,
138             kNotEqual_StencilFunc,
139             0xffff,
140             0x0000,
141             0xffff);
142 
143         pipelineBuilder->setStencil(kStencilPass);
144         SkAutoTUnref<GrDrawPathBatchBase> batch(
145                 GrDrawPathBatch::Create(viewMatrix, args.fColor, p->getFillType(), p));
146         args.fTarget->drawPathBatch(*pipelineBuilder, batch);
147     }
148 
149     pipelineBuilder->stencil()->setDisabled();
150     return true;
151 }
152