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) { |
| 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 |