Chromium Code Reviews| 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 | |
| 28 // path bounds would be empty. | |
| 29 bool get_shape_and_clip_bounds(int width, int height, | 39 bool get_shape_and_clip_bounds(int width, int height, |
|
robertphillips
2016/09/21 15:42:39
static here too ?
bsalomon
2016/09/21 16:01:09
Done.
| |
| 30 const GrClip& clip, | 40 const GrClip& clip, |
| 31 const GrShape& shape, | 41 const GrShape& shape, |
| 32 const SkMatrix& matrix, | 42 const SkMatrix& matrix, |
| 33 SkIRect* devShapeBounds, | 43 SkIRect* unclippedDevShapeBounds, |
| 44 SkIRect* clippedDevShapeBounds, | |
| 34 SkIRect* devClipBounds) { | 45 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 |
| 63 } | |
| 64 | |
| 65 void GrSoftwarePathRenderer::DrawNonAARect(GrDrawContext* drawContext, | 64 void GrSoftwarePathRenderer::DrawNonAARect(GrDrawContext* drawContext, |
| 66 const GrPaint& paint, | 65 const GrPaint& paint, |
| 67 const GrUserStencilSettings& userSten cilSettings, | 66 const GrUserStencilSettings& userSten cilSettings, |
| 68 const GrClip& clip, | 67 const GrClip& clip, |
| 69 const SkMatrix& viewMatrix, | 68 const SkMatrix& viewMatrix, |
| 70 const SkRect& rect, | 69 const SkRect& rect, |
| 71 const SkMatrix& localMatrix) { | 70 const SkMatrix& localMatrix) { |
| 72 SkAutoTUnref<GrDrawBatch> batch(GrRectBatchFactory::CreateNonAAFill(paint.ge tColor(), | 71 SkAutoTUnref<GrDrawBatch> batch(GrRectBatchFactory::CreateNonAAFill(paint.ge tColor(), |
| 73 viewMatr ix, rect, | 72 viewMatr ix, rect, |
| 74 nullptr, &localMatrix)); | 73 nullptr, &localMatrix)); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 126 if (!fTexProvider) { | 125 if (!fTexProvider) { |
| 127 return false; | 126 return false; |
| 128 } | 127 } |
| 129 | 128 |
| 130 // We really need to know if the shape will be inverse filled or not | 129 // We really need to know if the shape will be inverse filled or not |
| 131 bool inverseFilled = false; | 130 bool inverseFilled = false; |
| 132 SkTLazy<GrShape> tmpShape; | 131 SkTLazy<GrShape> tmpShape; |
| 133 SkASSERT(!args.fShape->style().applies()); | 132 SkASSERT(!args.fShape->style().applies()); |
| 134 inverseFilled = args.fShape->inverseFilled(); | 133 inverseFilled = args.fShape->inverseFilled(); |
| 135 | 134 |
| 136 SkIRect devShapeBounds, devClipBounds; | 135 SkIRect unclippedDevShapeBounds, clippedDevShapeBounds, devClipBounds; |
| 136 // To prevent overloading the cache with entries during animations we limit the cache of masks | |
| 137 // to cases where the matrix preserves axis alignment. | |
| 138 bool useCache = fAllowCaching && !inverseFilled && args.fViewMatrix->preserv esAxisAlignment() && | |
| 139 args.fShape->hasUnstyledKey() && args.fAntiAlias; | |
| 140 | |
| 137 if (!get_shape_and_clip_bounds(args.fDrawContext->width(), args.fDrawContext ->height(), | 141 if (!get_shape_and_clip_bounds(args.fDrawContext->width(), args.fDrawContext ->height(), |
| 138 *args.fClip, *args.fShape, | 142 *args.fClip, *args.fShape, |
| 139 *args.fViewMatrix, &devShapeBounds, &devClipB ounds)) { | 143 *args.fViewMatrix, &unclippedDevShapeBounds, |
| 144 &clippedDevShapeBounds, | |
| 145 &devClipBounds)) { | |
| 140 if (inverseFilled) { | 146 if (inverseFilled) { |
| 141 DrawAroundInvPath(args.fDrawContext, *args.fPaint, *args.fUserStenci lSettings, | 147 DrawAroundInvPath(args.fDrawContext, *args.fPaint, *args.fUserStenci lSettings, |
| 142 *args.fClip, | 148 *args.fClip, |
| 143 *args.fViewMatrix, devClipBounds, devShapeBounds); | 149 *args.fViewMatrix, devClipBounds, unclippedDevShap eBounds); |
| 144 | 150 |
| 145 } | 151 } |
| 146 return true; | 152 return true; |
| 147 } | 153 } |
| 148 | 154 |
| 149 SkAutoTUnref<GrTexture> texture( | 155 const SkIRect* boundsForMask = &clippedDevShapeBounds; |
| 150 GrSWMaskHelper::DrawShapeMaskToTexture(fTexProvider, *args.fShape, d evShapeBounds, | 156 if (useCache) { |
| 151 args.fAntiAlias, args.fViewMa trix)); | 157 // Use the cache only if >50% of the path is visible. |
| 152 if (!texture) { | 158 int unclippedWidth = unclippedDevShapeBounds.width(); |
| 153 return false; | 159 int unclippedHeight = unclippedDevShapeBounds.height(); |
| 160 int unclippedArea = unclippedWidth * unclippedHeight; | |
| 161 int clippedArea = clippedDevShapeBounds.width() * clippedDevShapeBounds. height(); | |
| 162 int maxTextureSize = args.fDrawContext->caps()->maxTextureSize(); | |
| 163 if (unclippedArea > 2 * clippedArea || unclippedWidth > maxTextureSize | | | |
| 164 unclippedHeight > maxTextureSize) { | |
| 165 useCache = false; | |
| 166 } else { | |
| 167 boundsForMask = &unclippedDevShapeBounds; | |
| 168 } | |
| 154 } | 169 } |
| 155 | 170 |
| 156 GrSWMaskHelper::DrawToTargetWithShapeMask(texture, args.fDrawContext, *args. fPaint, | 171 GrUniqueKey maskKey; |
| 172 struct KeyData { | |
| 173 SkScalar fFractionalTranslateX; | |
| 174 SkScalar fFractionalTranslateY; | |
| 175 }; | |
| 176 | |
| 177 if (useCache) { | |
| 178 // We require the upper left 2x2 of the matrix to match exactly for a ca che hit. | |
| 179 SkScalar sx = args.fViewMatrix->get(SkMatrix::kMScaleX); | |
| 180 SkScalar sy = args.fViewMatrix->get(SkMatrix::kMScaleY); | |
| 181 SkScalar kx = args.fViewMatrix->get(SkMatrix::kMSkewX); | |
| 182 SkScalar ky = args.fViewMatrix->get(SkMatrix::kMSkewY); | |
| 183 SkScalar tx = args.fViewMatrix->get(SkMatrix::kMTransX); | |
| 184 SkScalar ty = args.fViewMatrix->get(SkMatrix::kMTransY); | |
| 185 // Allow 8 bits each in x and y of subpixel positioning. | |
| 186 SkFixed fracX = SkScalarToFixed(SkScalarFraction(tx)) & 0x0000FF00; | |
| 187 SkFixed fracY = SkScalarToFixed(SkScalarFraction(ty)) & 0x0000FF00; | |
| 188 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain() ; | |
| 189 GrUniqueKey::Builder builder(&maskKey, kDomain, 5 + args.fShape->unstyle dKeySize()); | |
| 190 builder[0] = SkFloat2Bits(sx); | |
| 191 builder[1] = SkFloat2Bits(sy); | |
| 192 builder[2] = SkFloat2Bits(kx); | |
| 193 builder[3] = SkFloat2Bits(ky); | |
| 194 builder[4] = fracX | (fracY >> 8); | |
| 195 args.fShape->writeUnstyledKey(&builder[5]); | |
| 196 } | |
| 197 | |
| 198 sk_sp<GrTexture> texture; | |
| 199 if (useCache) { | |
| 200 texture.reset(args.fResourceProvider->findAndRefTextureByUniqueKey(maskK ey)); | |
| 201 } | |
| 202 if (!texture) { | |
| 203 GrSWMaskHelper::TextureType type = useCache ? GrSWMaskHelper::TextureTy pe::kExactFit | |
| 204 : GrSWMaskHelper::TextureTy pe::kApproximateFit; | |
| 205 texture.reset(GrSWMaskHelper::DrawShapeMaskToTexture(fTexProvider, *arg s.fShape, | |
| 206 *boundsForMask, ar gs.fAntiAlias, | |
| 207 type, args.fViewMa trix)); | |
| 208 if (!texture) { | |
| 209 return false; | |
| 210 } | |
| 211 if (useCache) { | |
| 212 texture->resourcePriv().setUniqueKey(maskKey); | |
| 213 } | |
| 214 } | |
| 215 | |
| 216 GrSWMaskHelper::DrawToTargetWithShapeMask(texture.get(), args.fDrawContext, *args.fPaint, | |
| 157 *args.fUserStencilSettings, | 217 *args.fUserStencilSettings, |
| 158 *args.fClip, *args.fViewMatrix, | 218 *args.fClip, *args.fViewMatrix, |
| 159 devShapeBounds); | 219 SkIPoint {boundsForMask->fLeft, bo undsForMask->fTop}, |
| 220 *boundsForMask); | |
| 160 | 221 |
| 161 if (inverseFilled) { | 222 if (inverseFilled) { |
| 162 DrawAroundInvPath(args.fDrawContext, *args.fPaint, *args.fUserStencilSet tings, | 223 DrawAroundInvPath(args.fDrawContext, *args.fPaint, *args.fUserStencilSet tings, |
| 163 *args.fClip, | 224 *args.fClip, |
| 164 *args.fViewMatrix, devClipBounds, devShapeBounds); | 225 *args.fViewMatrix, devClipBounds, unclippedDevShapeBou nds); |
| 165 } | 226 } |
| 166 | 227 |
| 167 return true; | 228 return true; |
| 168 } | 229 } |
| OLD | NEW |