OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "GrClipMaskManager.h" | 8 #include "GrClipMaskManager.h" |
9 #include "GrCaps.h" | 9 #include "GrCaps.h" |
10 #include "GrDrawContext.h" | 10 #include "GrDrawContext.h" |
11 #include "GrDrawTarget.h" | 11 #include "GrDrawTarget.h" |
12 #include "GrGpuResourcePriv.h" | 12 #include "GrGpuResourcePriv.h" |
13 #include "GrPaint.h" | 13 #include "GrPaint.h" |
14 #include "GrPathRenderer.h" | 14 #include "GrPathRenderer.h" |
15 #include "GrRenderTarget.h" | 15 #include "GrRenderTarget.h" |
16 #include "GrRenderTargetPriv.h" | 16 #include "GrRenderTargetPriv.h" |
17 #include "GrResourceProvider.h" | 17 #include "GrResourceProvider.h" |
18 #include "GrStencilAttachment.h" | 18 #include "GrStencilAttachment.h" |
19 #include "GrSWMaskHelper.h" | 19 #include "GrSWMaskHelper.h" |
20 #include "SkRasterClip.h" | 20 #include "SkRasterClip.h" |
21 #include "SkTLazy.h" | 21 #include "SkTLazy.h" |
22 #include "effects/GrConvexPolyEffect.h" | 22 #include "effects/GrConvexPolyEffect.h" |
23 #include "effects/GrPorterDuffXferProcessor.h" | 23 #include "effects/GrPorterDuffXferProcessor.h" |
24 #include "effects/GrRRectEffect.h" | 24 #include "effects/GrRRectEffect.h" |
25 #include "effects/GrTextureDomain.h" | 25 #include "effects/GrTextureDomain.h" |
26 | 26 |
27 typedef SkClipStack::Element Element; | 27 typedef SkClipStack::Element Element; |
28 | 28 |
29 //////////////////////////////////////////////////////////////////////////////// | 29 //////////////////////////////////////////////////////////////////////////////// |
30 namespace { | |
31 // set up the draw state to enable the aa clipping mask. Besides setting up the | 30 // set up the draw state to enable the aa clipping mask. Besides setting up the |
32 // stage matrix this also alters the vertex layout | 31 // stage matrix this also alters the vertex layout |
33 void setup_drawstate_aaclip(const GrPipelineBuilder& pipelineBuilder, | 32 static const GrFragmentProcessor* create_fp_for_mask(GrTexture* result, const Sk
IRect &devBound) { |
34 GrTexture* result, | |
35 GrPipelineBuilder::AutoRestoreFragmentProcessorState
* arfps, | |
36 const SkIRect &devBound) { | |
37 SkASSERT(arfps); | |
38 arfps->set(&pipelineBuilder); | |
39 | |
40 SkMatrix mat; | 33 SkMatrix mat; |
41 // We use device coords to compute the texture coordinates. We set our matri
x to be a | 34 // We use device coords to compute the texture coordinates. We set our matri
x to be a |
42 // translation to the devBound, and then a scaling matrix to normalized coor
ds. | 35 // translation to the devBound, and then a scaling matrix to normalized coor
ds. |
43 mat.setIDiv(result->width(), result->height()); | 36 mat.setIDiv(result->width(), result->height()); |
44 mat.preTranslate(SkIntToScalar(-devBound.fLeft), | 37 mat.preTranslate(SkIntToScalar(-devBound.fLeft), |
45 SkIntToScalar(-devBound.fTop)); | 38 SkIntToScalar(-devBound.fTop)); |
46 | 39 |
47 SkIRect domainTexels = SkIRect::MakeWH(devBound.width(), devBound.height()); | 40 SkIRect domainTexels = SkIRect::MakeWH(devBound.width(), devBound.height()); |
48 // This could be a long-lived effect that is cached with the alpha-mask. | 41 return GrTextureDomainEffect::Create(result, |
49 arfps->addCoverageFragmentProcessor( | 42 mat, |
50 GrTextureDomainEffect::Create(result, | 43 GrTextureDomain::MakeTexelDomain(result
, domainTexels), |
51 mat, | 44 GrTextureDomain::kDecal_Mode, |
52 GrTextureDomain::MakeTexelDomain(result, d
omainTexels), | 45 GrTextureParams::kNone_FilterMode, |
53 GrTextureDomain::kDecal_Mode, | 46 kDevice_GrCoordSet); |
54 GrTextureParams::kNone_FilterMode, | |
55 kDevice_GrCoordSet))->unref(); | |
56 } | 47 } |
57 | 48 |
58 bool path_needs_SW_renderer(GrContext* context, | 49 static bool path_needs_SW_renderer(GrContext* context, |
59 const GrDrawTarget* gpu, | 50 const GrDrawTarget* gpu, |
60 const GrPipelineBuilder& pipelineBuilder, | 51 const GrPipelineBuilder& pipelineBuilder, |
61 const SkMatrix& viewMatrix, | 52 const SkMatrix& viewMatrix, |
62 const SkPath& origPath, | 53 const SkPath& origPath, |
63 const GrStrokeInfo& stroke, | 54 const GrStrokeInfo& stroke, |
64 bool doAA) { | 55 bool doAA) { |
65 // the gpu alpha mask will draw the inverse paths as non-inverse to a temp b
uffer | 56 // the gpu alpha mask will draw the inverse paths as non-inverse to a temp b
uffer |
66 SkTCopyOnFirstWrite<SkPath> path(origPath); | 57 SkTCopyOnFirstWrite<SkPath> path(origPath); |
67 if (path->isInverseFillType()) { | 58 if (path->isInverseFillType()) { |
68 path.writable()->toggleInverseFillType(); | 59 path.writable()->toggleInverseFillType(); |
69 } | 60 } |
70 // last (false) parameter disallows use of the SW path renderer | 61 // last (false) parameter disallows use of the SW path renderer |
71 GrPathRendererChain::DrawType type = doAA ? | 62 GrPathRendererChain::DrawType type = doAA ? |
72 GrPathRendererChain::kColorAntiAlias_Dr
awType : | 63 GrPathRendererChain::kColorAntiAlias_Dr
awType : |
73 GrPathRendererChain::kColor_DrawType; | 64 GrPathRendererChain::kColor_DrawType; |
74 | 65 |
75 return nullptr == context->getPathRenderer(gpu, &pipelineBuilder, viewMatrix
, *path, stroke, | 66 return nullptr == context->getPathRenderer(gpu, &pipelineBuilder, viewMatrix
, *path, stroke, |
76 false, type); | 67 false, type); |
77 } | 68 } |
78 } | |
79 | 69 |
80 GrClipMaskManager::GrClipMaskManager(GrDrawTarget* drawTarget) | 70 GrClipMaskManager::GrClipMaskManager(GrDrawTarget* drawTarget) |
81 : fCurrClipMaskType(kNone_ClipMaskType) | 71 : fCurrClipMaskType(kNone_ClipMaskType) |
82 , fDrawTarget(drawTarget) | 72 , fDrawTarget(drawTarget) |
83 , fClipMode(kIgnoreClip_StencilClipMode) { | 73 , fClipMode(kIgnoreClip_StencilClipMode) { |
84 } | 74 } |
85 | 75 |
86 GrContext* GrClipMaskManager::getContext() { return fDrawTarget->cmmAccess().con
text(); } | 76 GrContext* GrClipMaskManager::getContext() { return fDrawTarget->cmmAccess().con
text(); } |
87 | 77 |
88 /* | 78 /* |
(...skipping 23 matching lines...) Expand all Loading... |
112 element->asPath(&path); | 102 element->asPath(&path); |
113 if (path_needs_SW_renderer(this->getContext(), fDrawTarget, pipeline
Builder, translate, | 103 if (path_needs_SW_renderer(this->getContext(), fDrawTarget, pipeline
Builder, translate, |
114 path, stroke, element->isAA())) { | 104 path, stroke, element->isAA())) { |
115 return true; | 105 return true; |
116 } | 106 } |
117 } | 107 } |
118 } | 108 } |
119 return false; | 109 return false; |
120 } | 110 } |
121 | 111 |
122 bool GrClipMaskManager::installClipEffects( | 112 const GrFragmentProcessor* GrClipMaskManager::getAnalyticClipProcessor( |
123 const GrPipelineBuilder& pipelineBuilder, | 113 const GrReducedClip::Ele
mentList& elements, |
124 GrPipelineBuilder::AutoRestoreFragmentProcessorState* arfps, | 114 const SkVector& clipToRT
Offset, |
125 const GrReducedClip::ElementList& elements, | 115 const SkRect* drawBounds
) { |
126 const SkVector& clipToRTOffset, | |
127 const SkRect* drawBounds) { | |
128 SkRect boundsInClipSpace; | 116 SkRect boundsInClipSpace; |
129 if (drawBounds) { | 117 if (drawBounds) { |
130 boundsInClipSpace = *drawBounds; | 118 boundsInClipSpace = *drawBounds; |
131 boundsInClipSpace.offset(-clipToRTOffset.fX, -clipToRTOffset.fY); | 119 boundsInClipSpace.offset(-clipToRTOffset.fX, -clipToRTOffset.fY); |
132 } | 120 } |
133 | 121 SkASSERT(elements.count() <= kMaxAnalyticElements); |
134 arfps->set(&pipelineBuilder); | 122 const GrFragmentProcessor* fps[kMaxAnalyticElements]; |
135 GrRenderTarget* rt = pipelineBuilder.getRenderTarget(); | 123 for (int i = 0; i < kMaxAnalyticElements; ++i) { |
| 124 fps[i] = nullptr; |
| 125 } |
| 126 int fpCnt = 0; |
136 GrReducedClip::ElementList::Iter iter(elements); | 127 GrReducedClip::ElementList::Iter iter(elements); |
137 bool failed = false; | 128 bool failed = false; |
138 while (iter.get()) { | 129 while (iter.get()) { |
139 SkRegion::Op op = iter.get()->getOp(); | 130 SkRegion::Op op = iter.get()->getOp(); |
140 bool invert; | 131 bool invert; |
141 bool skip = false; | 132 bool skip = false; |
142 switch (op) { | 133 switch (op) { |
143 case SkRegion::kReplace_Op: | 134 case SkRegion::kReplace_Op: |
144 SkASSERT(iter.get() == elements.head()); | 135 SkASSERT(iter.get() == elements.head()); |
145 // Fallthrough, handled same as intersect. | 136 // Fallthrough, handled same as intersect. |
(...skipping 12 matching lines...) Expand all Loading... |
158 failed = true; | 149 failed = true; |
159 break; | 150 break; |
160 } | 151 } |
161 if (failed) { | 152 if (failed) { |
162 break; | 153 break; |
163 } | 154 } |
164 | 155 |
165 if (!skip) { | 156 if (!skip) { |
166 GrPrimitiveEdgeType edgeType; | 157 GrPrimitiveEdgeType edgeType; |
167 if (iter.get()->isAA()) { | 158 if (iter.get()->isAA()) { |
168 if (rt->isUnifiedMultisampled()) { | |
169 // Coverage based AA clips don't place nicely with MSAA. | |
170 failed = true; | |
171 break; | |
172 } | |
173 edgeType = | 159 edgeType = |
174 invert ? kInverseFillAA_GrProcessorEdgeType : kFillAA_Gr
ProcessorEdgeType; | 160 invert ? kInverseFillAA_GrProcessorEdgeType : kFillAA_GrProc
essorEdgeType; |
175 } else { | 161 } else { |
176 edgeType = invert ? kInverseFillBW_GrProcessorEdgeType : | 162 edgeType = |
177 kFillBW_GrProcessorEdgeType; | 163 invert ? kInverseFillBW_GrProcessorEdgeType : kFillBW_GrProc
essorEdgeType; |
178 } | 164 } |
179 SkAutoTUnref<GrFragmentProcessor> fp; | |
180 switch (iter.get()->getType()) { | 165 switch (iter.get()->getType()) { |
181 case SkClipStack::Element::kPath_Type: | 166 case SkClipStack::Element::kPath_Type: |
182 fp.reset(GrConvexPolyEffect::Create(edgeType, iter.get()->ge
tPath(), | 167 fps[fpCnt] = GrConvexPolyEffect::Create(edgeType, iter.get()
->getPath(), |
183 &clipToRTOffset)); | 168 &clipToRTOffset); |
184 break; | 169 break; |
185 case SkClipStack::Element::kRRect_Type: { | 170 case SkClipStack::Element::kRRect_Type: { |
186 SkRRect rrect = iter.get()->getRRect(); | 171 SkRRect rrect = iter.get()->getRRect(); |
187 rrect.offset(clipToRTOffset.fX, clipToRTOffset.fY); | 172 rrect.offset(clipToRTOffset.fX, clipToRTOffset.fY); |
188 fp.reset(GrRRectEffect::Create(edgeType, rrect)); | 173 fps[fpCnt] = GrRRectEffect::Create(edgeType, rrect); |
189 break; | 174 break; |
190 } | 175 } |
191 case SkClipStack::Element::kRect_Type: { | 176 case SkClipStack::Element::kRect_Type: { |
192 SkRect rect = iter.get()->getRect(); | 177 SkRect rect = iter.get()->getRect(); |
193 rect.offset(clipToRTOffset.fX, clipToRTOffset.fY); | 178 rect.offset(clipToRTOffset.fX, clipToRTOffset.fY); |
194 fp.reset(GrConvexPolyEffect::Create(edgeType, rect)); | 179 fps[fpCnt] = GrConvexPolyEffect::Create(edgeType, rect); |
195 break; | 180 break; |
196 } | 181 } |
197 default: | 182 default: |
198 break; | 183 break; |
199 } | 184 } |
200 if (fp) { | 185 if (!fps[fpCnt]) { |
201 arfps->addCoverageFragmentProcessor(fp); | |
202 } else { | |
203 failed = true; | 186 failed = true; |
204 break; | 187 break; |
205 } | 188 } |
| 189 fpCnt++; |
206 } | 190 } |
207 iter.next(); | 191 iter.next(); |
208 } | 192 } |
209 | 193 |
210 if (failed) { | 194 const GrFragmentProcessor* resultFP = nullptr; |
211 arfps->set(nullptr); | 195 if (!failed) { |
| 196 resultFP = GrFragmentProcessor::RunInSeries(fps, fpCnt); |
212 } | 197 } |
213 return !failed; | 198 for (int i = 0; i < fpCnt; ++i) { |
| 199 fps[i]->unref(); |
| 200 } |
| 201 return resultFP; |
214 } | 202 } |
215 | 203 |
216 //////////////////////////////////////////////////////////////////////////////// | 204 //////////////////////////////////////////////////////////////////////////////// |
217 // sort out what kind of clip mask needs to be created: alpha, stencil, | 205 // sort out what kind of clip mask needs to be created: alpha, stencil, |
218 // scissor, or entirely software | 206 // scissor, or entirely software |
219 bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder, | 207 bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder, |
220 GrPipelineBuilder::AutoRestoreFragmentProc
essorState* arfps, | |
221 GrPipelineBuilder::AutoRestoreStencil* ars
, | 208 GrPipelineBuilder::AutoRestoreStencil* ars
, |
222 GrScissorState* scissorState, | 209 GrScissorState* scissorState, |
223 const SkRect* devBounds) { | 210 const SkRect* devBounds, |
| 211 GrAppliedClip* out) { |
224 fCurrClipMaskType = kNone_ClipMaskType; | 212 fCurrClipMaskType = kNone_ClipMaskType; |
225 if (kRespectClip_StencilClipMode == fClipMode) { | 213 if (kRespectClip_StencilClipMode == fClipMode) { |
226 fClipMode = kIgnoreClip_StencilClipMode; | 214 fClipMode = kIgnoreClip_StencilClipMode; |
227 } | 215 } |
228 | 216 |
229 GrReducedClip::ElementList elements(16); | 217 GrReducedClip::ElementList elements(16); |
230 int32_t genID = 0; | 218 int32_t genID = 0; |
231 GrReducedClip::InitialState initialState = GrReducedClip::kAllIn_InitialStat
e; | 219 GrReducedClip::InitialState initialState = GrReducedClip::kAllIn_InitialStat
e; |
232 SkIRect clipSpaceIBounds; | 220 SkIRect clipSpaceIBounds; |
233 bool requiresAA = false; | 221 bool requiresAA = false; |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
281 } | 269 } |
282 | 270 |
283 // An element count of 4 was chosen because of the common pattern in Blink o
f: | 271 // An element count of 4 was chosen because of the common pattern in Blink o
f: |
284 // isect RR | 272 // isect RR |
285 // diff RR | 273 // diff RR |
286 // isect convex_poly | 274 // isect convex_poly |
287 // isect convex_poly | 275 // isect convex_poly |
288 // when drawing rounded div borders. This could probably be tuned based on a | 276 // when drawing rounded div borders. This could probably be tuned based on a |
289 // configuration's relative costs of switching RTs to generate a mask vs | 277 // configuration's relative costs of switching RTs to generate a mask vs |
290 // longer shaders. | 278 // longer shaders. |
291 if (elements.count() <= 4) { | 279 if (elements.count() <= kMaxAnalyticElements) { |
292 SkVector clipToRTOffset = { SkIntToScalar(-clip.origin().fX), | 280 SkVector clipToRTOffset = { SkIntToScalar(-clip.origin().fX), |
293 SkIntToScalar(-clip.origin().fY) }; | 281 SkIntToScalar(-clip.origin().fY) }; |
| 282 // When there are multiple color samples we want to do per-sample clippi
ng, not compute |
| 283 // a fractional pixel coverage. |
| 284 bool disallowAnalyticAA = pipelineBuilder.getRenderTarget()->isUnifiedMu
ltisampled(); |
| 285 const GrFragmentProcessor* clipFP = nullptr; |
294 if (elements.isEmpty() || | 286 if (elements.isEmpty() || |
295 (requiresAA && this->installClipEffects(pipelineBuilder, arfps, elem
ents, clipToRTOffset, | 287 (requiresAA && !disallowAnalyticAA && |
296 devBounds))) { | 288 SkToBool(clipFP = this->getAnalyticClipProcessor(elements, clipToRT
Offset, devBounds)))) { |
297 SkIRect scissorSpaceIBounds(clipSpaceIBounds); | 289 SkIRect scissorSpaceIBounds(clipSpaceIBounds); |
298 scissorSpaceIBounds.offset(-clip.origin()); | 290 scissorSpaceIBounds.offset(-clip.origin()); |
299 if (nullptr == devBounds || | 291 if (nullptr == devBounds || |
300 !SkRect::Make(scissorSpaceIBounds).contains(*devBounds)) { | 292 !SkRect::Make(scissorSpaceIBounds).contains(*devBounds)) { |
301 scissorState->set(scissorSpaceIBounds); | 293 scissorState->set(scissorSpaceIBounds); |
302 } | 294 } |
303 this->setPipelineBuilderStencil(pipelineBuilder, ars); | 295 this->setPipelineBuilderStencil(pipelineBuilder, ars); |
| 296 out->fClipCoverageFP.reset(clipFP); |
304 return true; | 297 return true; |
305 } | 298 } |
306 } | 299 } |
307 | 300 |
308 // If MSAA is enabled we can do everything in the stencil buffer. | 301 // If MSAA is enabled we can do everything in the stencil buffer. |
309 if (0 == rt->numStencilSamples() && requiresAA) { | 302 if (0 == rt->numStencilSamples() && requiresAA) { |
310 SkAutoTUnref<GrTexture> result; | 303 SkAutoTUnref<GrTexture> result; |
311 | 304 |
312 // The top-left of the mask corresponds to the top-left corner of the bo
unds. | 305 // The top-left of the mask corresponds to the top-left corner of the bo
unds. |
313 SkVector clipToMaskOffset = { | 306 SkVector clipToMaskOffset = { |
(...skipping 11 matching lines...) Expand all Loading... |
325 clipSpaceIBounds)); | 318 clipSpaceIBounds)); |
326 } else { | 319 } else { |
327 result.reset(this->createAlphaClipMask(genID, | 320 result.reset(this->createAlphaClipMask(genID, |
328 initialState, | 321 initialState, |
329 elements, | 322 elements, |
330 clipToMaskOffset, | 323 clipToMaskOffset, |
331 clipSpaceIBounds)); | 324 clipSpaceIBounds)); |
332 } | 325 } |
333 | 326 |
334 if (result) { | 327 if (result) { |
335 arfps->set(&pipelineBuilder); | |
336 // The mask's top left coord should be pinned to the rounded-out top
left corner of | 328 // The mask's top left coord should be pinned to the rounded-out top
left corner of |
337 // clipSpace bounds. We determine the mask's position WRT to the ren
der target here. | 329 // clipSpace bounds. We determine the mask's position WRT to the ren
der target here. |
338 SkIRect rtSpaceMaskBounds = clipSpaceIBounds; | 330 SkIRect rtSpaceMaskBounds = clipSpaceIBounds; |
339 rtSpaceMaskBounds.offset(-clip.origin()); | 331 rtSpaceMaskBounds.offset(-clip.origin()); |
340 setup_drawstate_aaclip(pipelineBuilder, result, arfps, rtSpaceMaskBo
unds); | 332 out->fClipCoverageFP.reset(create_fp_for_mask(result, rtSpaceMaskBou
nds)); |
341 this->setPipelineBuilderStencil(pipelineBuilder, ars); | 333 this->setPipelineBuilderStencil(pipelineBuilder, ars); |
342 return true; | 334 return true; |
343 } | 335 } |
344 // if alpha clip mask creation fails fall through to the non-AA code pat
hs | 336 // if alpha clip mask creation fails fall through to the non-AA code pat
hs |
345 } | 337 } |
346 | 338 |
347 // use the stencil clip if we can't represent the clip as a rectangle. | 339 // use the stencil clip if we can't represent the clip as a rectangle. |
348 SkIPoint clipSpaceToStencilSpaceOffset = -clip.origin(); | 340 SkIPoint clipSpaceToStencilSpaceOffset = -clip.origin(); |
349 this->createStencilClipMask(rt, | 341 this->createStencilClipMask(rt, |
350 genID, | 342 genID, |
(...skipping 781 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1132 | 1124 |
1133 //////////////////////////////////////////////////////////////////////////////// | 1125 //////////////////////////////////////////////////////////////////////////////// |
1134 | 1126 |
1135 void GrClipMaskManager::adjustPathStencilParams(const GrStencilAttachment* stenc
ilAttachment, | 1127 void GrClipMaskManager::adjustPathStencilParams(const GrStencilAttachment* stenc
ilAttachment, |
1136 GrStencilSettings* settings) { | 1128 GrStencilSettings* settings) { |
1137 if (stencilAttachment) { | 1129 if (stencilAttachment) { |
1138 int stencilBits = stencilAttachment->bits(); | 1130 int stencilBits = stencilAttachment->bits(); |
1139 this->adjustStencilParams(settings, fClipMode, stencilBits); | 1131 this->adjustStencilParams(settings, fClipMode, stencilBits); |
1140 } | 1132 } |
1141 } | 1133 } |
OLD | NEW |