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 "GrSoftwarePathRenderer.h" | 8 #include "GrSoftwarePathRenderer.h" |
9 #include "GrAuditTrail.h" | 9 #include "GrAuditTrail.h" |
10 #include "GrClip.h" | 10 #include "GrClip.h" |
11 #include "GrPipelineBuilder.h" | 11 #include "GrPipelineBuilder.h" |
12 #include "GrGpuResourcePriv.h" | |
12 #include "GrSWMaskHelper.h" | 13 #include "GrSWMaskHelper.h" |
13 #include "GrTextureProvider.h" | 14 #include "GrTextureProvider.h" |
14 #include "batches/GrRectBatchFactory.h" | 15 #include "batches/GrRectBatchFactory.h" |
15 | 16 |
16 //////////////////////////////////////////////////////////////////////////////// | 17 //////////////////////////////////////////////////////////////////////////////// |
17 bool GrSoftwarePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { | 18 bool GrSoftwarePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { |
18 // Pass on any style that applies. The caller will apply the style if a suit able renderer is | 19 // Pass on any style that applies. The caller will apply the style if a suit able renderer is |
19 // not found and try again with the new GrShape. | 20 // not found and try again with the new GrShape. |
20 return !args.fShape->style().applies() && SkToBool(fTexProvider); | 21 return !args.fShape->style().applies() && SkToBool(fTexProvider); |
21 } | 22 } |
22 | 23 |
23 namespace { | 24 //////////////////////////////////////////////////////////////////////////////// |
25 static bool get_unclipped_shape_dev_bounds(const GrShape& shape, const SkMatrix& matrix, | |
26 SkIRect* devBounds) { | |
27 SkRect shapeBounds = shape.styledBounds(); | |
28 if (shapeBounds.isEmpty()) { | |
29 return false; | |
30 } | |
31 SkRect shapeDevBounds; | |
32 matrix.mapRect(&shapeDevBounds, shapeBounds); | |
33 shapeDevBounds.roundOut(devBounds); | |
34 return true; | |
35 } | |
24 | 36 |
25 //////////////////////////////////////////////////////////////////////////////// | 37 // Gets the shape bounds, the clip bounds, and the intersection (if any). Return s false if there |
26 // gets device coord bounds of path (not considering the fill) and clip. The | 38 // is no intersection. |
27 // path bounds will be a subset of the clip bounds. returns false if | 39 static bool get_shape_and_clip_bounds(int width, int height, |
28 // path bounds would be empty. | 40 const GrClip& clip, |
29 bool get_shape_and_clip_bounds(int width, int height, | 41 const GrShape& shape, |
30 const GrClip& clip, | 42 const SkMatrix& matrix, |
31 const GrShape& shape, | 43 SkIRect* unclippedDevShapeBounds, |
32 const SkMatrix& matrix, | 44 SkIRect* clippedDevShapeBounds, |
33 SkIRect* devShapeBounds, | 45 SkIRect* devClipBounds) { |
34 SkIRect* devClipBounds) { | |
35 // compute bounds as intersection of rt size, clip, and path | 46 // compute bounds as intersection of rt size, clip, and path |
36 clip.getConservativeBounds(width, height, devClipBounds); | 47 clip.getConservativeBounds(width, height, devClipBounds); |
37 | 48 |
38 if (devClipBounds->isEmpty()) { | 49 if (!get_unclipped_shape_dev_bounds(shape, matrix, unclippedDevShapeBounds)) { |
39 *devShapeBounds = SkIRect::MakeWH(width, height); | 50 *unclippedDevShapeBounds = SkIRect::EmptyIRect(); |
51 *clippedDevShapeBounds = SkIRect::EmptyIRect(); | |
40 return false; | 52 return false; |
41 } | 53 } |
42 SkRect shapeBounds = shape.styledBounds(); | 54 if (!clippedDevShapeBounds->intersect(*devClipBounds, *unclippedDevShapeBoun ds)) { |
43 if (!shapeBounds.isEmpty()) { | 55 *clippedDevShapeBounds = SkIRect::EmptyIRect(); |
44 SkRect shapeSBounds; | |
45 matrix.mapRect(&shapeSBounds, shapeBounds); | |
46 SkIRect shapeIBounds; | |
47 shapeSBounds.roundOut(&shapeIBounds); | |
48 *devShapeBounds = *devClipBounds; | |
49 if (!devShapeBounds->intersect(shapeIBounds)) { | |
50 // set the correct path bounds, as this would be used later. | |
51 *devShapeBounds = shapeIBounds; | |
52 return false; | |
53 } | |
54 } else { | |
55 *devShapeBounds = SkIRect::EmptyIRect(); | |
56 return false; | 56 return false; |
57 } | 57 } |
58 return true; | 58 return true; |
59 } | 59 } |
60 | 60 |
61 //////////////////////////////////////////////////////////////////////////////// | 61 //////////////////////////////////////////////////////////////////////////////// |
62 | 62 |
63 } | |
64 | |
65 void GrSoftwarePathRenderer::DrawNonAARect(GrDrawContext* drawContext, | 63 void GrSoftwarePathRenderer::DrawNonAARect(GrDrawContext* drawContext, |
66 const GrPaint& paint, | 64 const GrPaint& paint, |
67 const GrUserStencilSettings& userSten cilSettings, | 65 const GrUserStencilSettings& userSten cilSettings, |
68 const GrClip& clip, | 66 const GrClip& clip, |
69 const SkMatrix& viewMatrix, | 67 const SkMatrix& viewMatrix, |
70 const SkRect& rect, | 68 const SkRect& rect, |
71 const SkMatrix& localMatrix) { | 69 const SkMatrix& localMatrix) { |
72 SkAutoTUnref<GrDrawBatch> batch(GrRectBatchFactory::CreateNonAAFill(paint.ge tColor(), | 70 SkAutoTUnref<GrDrawBatch> batch(GrRectBatchFactory::CreateNonAAFill(paint.ge tColor(), |
73 viewMatr ix, rect, | 71 viewMatr ix, rect, |
74 nullptr, &localMatrix)); | 72 nullptr, &localMatrix)); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
126 if (!fTexProvider) { | 124 if (!fTexProvider) { |
127 return false; | 125 return false; |
128 } | 126 } |
129 | 127 |
130 // We really need to know if the shape will be inverse filled or not | 128 // We really need to know if the shape will be inverse filled or not |
131 bool inverseFilled = false; | 129 bool inverseFilled = false; |
132 SkTLazy<GrShape> tmpShape; | 130 SkTLazy<GrShape> tmpShape; |
133 SkASSERT(!args.fShape->style().applies()); | 131 SkASSERT(!args.fShape->style().applies()); |
134 inverseFilled = args.fShape->inverseFilled(); | 132 inverseFilled = args.fShape->inverseFilled(); |
135 | 133 |
136 SkIRect devShapeBounds, devClipBounds; | 134 SkIRect unclippedDevShapeBounds, clippedDevShapeBounds, devClipBounds; |
135 // To prevent overloading the cache with entries during animations we limit the cache of masks | |
136 // to cases where the matrix preserves axis alignment. | |
137 bool useCache = fAllowCaching && !inverseFilled && args.fViewMatrix->preserv esAxisAlignment() && | |
138 args.fShape->hasUnstyledKey() && args.fAntiAlias; | |
139 | |
137 if (!get_shape_and_clip_bounds(args.fDrawContext->width(), args.fDrawContext ->height(), | 140 if (!get_shape_and_clip_bounds(args.fDrawContext->width(), args.fDrawContext ->height(), |
138 *args.fClip, *args.fShape, | 141 *args.fClip, *args.fShape, |
139 *args.fViewMatrix, &devShapeBounds, &devClipB ounds)) { | 142 *args.fViewMatrix, &unclippedDevShapeBounds, |
143 &clippedDevShapeBounds, | |
144 &devClipBounds)) { | |
140 if (inverseFilled) { | 145 if (inverseFilled) { |
141 DrawAroundInvPath(args.fDrawContext, *args.fPaint, *args.fUserStenci lSettings, | 146 DrawAroundInvPath(args.fDrawContext, *args.fPaint, *args.fUserStenci lSettings, |
142 *args.fClip, | 147 *args.fClip, |
143 *args.fViewMatrix, devClipBounds, devShapeBounds); | 148 *args.fViewMatrix, devClipBounds, unclippedDevShap eBounds); |
144 | 149 |
145 } | 150 } |
146 return true; | 151 return true; |
147 } | 152 } |
148 | 153 |
149 SkAutoTUnref<GrTexture> texture( | 154 const SkIRect* boundsForMask = &clippedDevShapeBounds; |
150 GrSWMaskHelper::DrawShapeMaskToTexture(fTexProvider, *args.fShape, d evShapeBounds, | 155 if (useCache) { |
151 args.fAntiAlias, args.fViewMa trix)); | 156 // Use the cache only if >50% of the path is visible. |
152 if (!texture) { | 157 int unclippedWidth = unclippedDevShapeBounds.width(); |
153 return false; | 158 int unclippedHeight = unclippedDevShapeBounds.height(); |
159 int unclippedArea = unclippedWidth * unclippedHeight; | |
160 int clippedArea = clippedDevShapeBounds.width() * clippedDevShapeBounds. height(); | |
161 int maxTextureSize = args.fDrawContext->caps()->maxTextureSize(); | |
162 if (unclippedArea > 2 * clippedArea || unclippedWidth > maxTextureSize | | | |
163 unclippedHeight > maxTextureSize) { | |
164 useCache = false; | |
165 } else { | |
166 boundsForMask = &unclippedDevShapeBounds; | |
167 } | |
154 } | 168 } |
155 | 169 |
156 GrSWMaskHelper::DrawToTargetWithShapeMask(texture, args.fDrawContext, *args. fPaint, | 170 GrUniqueKey maskKey; |
171 struct KeyData { | |
172 SkScalar fFractionalTranslateX; | |
173 SkScalar fFractionalTranslateY; | |
174 }; | |
175 | |
176 if (useCache) { | |
177 // We require the upper left 2x2 of the matrix to match exactly for a ca che hit. | |
178 SkScalar sx = args.fViewMatrix->get(SkMatrix::kMScaleX); | |
179 SkScalar sy = args.fViewMatrix->get(SkMatrix::kMScaleY); | |
180 SkScalar kx = args.fViewMatrix->get(SkMatrix::kMSkewX); | |
181 SkScalar ky = args.fViewMatrix->get(SkMatrix::kMSkewY); | |
182 SkScalar tx = args.fViewMatrix->get(SkMatrix::kMTransX); | |
183 SkScalar ty = args.fViewMatrix->get(SkMatrix::kMTransY); | |
184 // Allow 8 bits each in x and y of subpixel positioning. | |
185 SkFixed fracX = SkScalarToFixed(SkScalarFraction(tx)) & 0x0000FF00; | |
186 SkFixed fracY = SkScalarToFixed(SkScalarFraction(ty)) & 0x0000FF00; | |
187 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain() ; | |
188 GrUniqueKey::Builder builder(&maskKey, kDomain, 5 + args.fShape->unstyle dKeySize()); | |
189 builder[0] = SkFloat2Bits(sx); | |
190 builder[1] = SkFloat2Bits(sy); | |
191 builder[2] = SkFloat2Bits(kx); | |
192 builder[3] = SkFloat2Bits(ky); | |
193 builder[4] = fracX | (fracY >> 8); | |
194 args.fShape->writeUnstyledKey(&builder[5]); | |
195 } | |
196 | |
197 sk_sp<GrTexture> texture; | |
198 if (useCache) { | |
199 texture.reset(args.fResourceProvider->findAndRefTextureByUniqueKey(maskK ey)); | |
200 } | |
201 if (!texture) { | |
202 GrSWMaskHelper::TextureType type = useCache ? GrSWMaskHelper::TextureTy pe::kExactFit | |
203 : GrSWMaskHelper::TextureTy pe::kApproximateFit; | |
204 texture.reset(GrSWMaskHelper::DrawShapeMaskToTexture(fTexProvider, *arg s.fShape, | |
205 *boundsForMask, ar gs.fAntiAlias, | |
206 type, args.fViewMa trix)); | |
207 if (!texture) { | |
robertphillips
2016/09/21 16:37:15
Is there something odd w/ the indent here ?
bsalomon
2016/09/21 17:34:10
Done.
| |
208 return false; | |
209 } | |
210 if (useCache) { | |
211 texture->resourcePriv().setUniqueKey(maskKey); | |
212 } | |
213 } | |
214 | |
215 GrSWMaskHelper::DrawToTargetWithShapeMask(texture.get(), args.fDrawContext, *args.fPaint, | |
157 *args.fUserStencilSettings, | 216 *args.fUserStencilSettings, |
158 *args.fClip, *args.fViewMatrix, | 217 *args.fClip, *args.fViewMatrix, |
159 devShapeBounds); | 218 SkIPoint {boundsForMask->fLeft, bo undsForMask->fTop}, |
219 *boundsForMask); | |
160 | 220 |
161 if (inverseFilled) { | 221 if (inverseFilled) { |
162 DrawAroundInvPath(args.fDrawContext, *args.fPaint, *args.fUserStencilSet tings, | 222 DrawAroundInvPath(args.fDrawContext, *args.fPaint, *args.fUserStencilSet tings, |
163 *args.fClip, | 223 *args.fClip, |
164 *args.fViewMatrix, devClipBounds, devShapeBounds); | 224 *args.fViewMatrix, devClipBounds, unclippedDevShapeBou nds); |
165 } | 225 } |
166 | 226 |
167 return true; | 227 return true; |
168 } | 228 } |
OLD | NEW |