| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 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 "GrTessellatingPathRenderer.h" | 8 #include "GrTessellatingPathRenderer.h" |
| 9 | 9 |
| 10 #include "GrAuditTrail.h" | 10 #include "GrAuditTrail.h" |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 98 bool fCanMapVB; | 98 bool fCanMapVB; |
| 99 SkPoint* fVertices; | 99 SkPoint* fVertices; |
| 100 }; | 100 }; |
| 101 | 101 |
| 102 } // namespace | 102 } // namespace |
| 103 | 103 |
| 104 GrTessellatingPathRenderer::GrTessellatingPathRenderer() { | 104 GrTessellatingPathRenderer::GrTessellatingPathRenderer() { |
| 105 } | 105 } |
| 106 | 106 |
| 107 bool GrTessellatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) cons
t { | 107 bool GrTessellatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) cons
t { |
| 108 // This path renderer can draw all fill styles, all stroke styles except hai
rlines, but does | 108 // This path renderer can draw fill styles but does not do antialiasing. It
can do convex and |
| 109 // not do antialiasing. It can do convex and concave paths, but we'll leave
the convex ones to | 109 // concave paths, but we'll leave the convex ones to simpler algorithms. We
pass on paths that |
| 110 // simpler algorithms. Similary, we skip the non-hairlines that can be treat
ed as hairline. | 110 // have styles, though they may come back around after applying the styling
information to the |
| 111 // An arbitrary path effect could produce a hairline result so we pass on th
ose. | 111 // geometry to create a filled path. We also skip paths that don't have a ke
y since the real |
| 112 return !IsStrokeHairlineOrEquivalent(args.fShape->style(), *args.fViewMatrix
, nullptr) && | 112 // advantage of this path renderer comes from caching the tessellated geomet
ry. |
| 113 !args.fShape->style().strokeRec().isHairlineStyle() && | 113 return !args.fShape->style().applies() && args.fShape->style().isSimpleFill(
) && |
| 114 !args.fShape->style().hasNonDashPathEffect() && !args.fAntiAlias && | 114 !args.fAntiAlias && args.fShape->hasUnstyledKey() && !args.fShape->kn
ownToBeConvex(); |
| 115 !args.fShape->knownToBeConvex(); | |
| 116 } | 115 } |
| 117 | 116 |
| 118 class TessellatingPathBatch : public GrVertexBatch { | 117 class TessellatingPathBatch : public GrVertexBatch { |
| 119 public: | 118 public: |
| 120 DEFINE_BATCH_CLASS_ID | 119 DEFINE_BATCH_CLASS_ID |
| 121 | 120 |
| 122 static GrDrawBatch* Create(const GrColor& color, | 121 static GrDrawBatch* Create(const GrColor& color, |
| 123 const SkPath& path, | 122 const GrShape& shape, |
| 124 const GrStyle& style, | |
| 125 const SkMatrix& viewMatrix, | 123 const SkMatrix& viewMatrix, |
| 126 SkRect clipBounds) { | 124 SkRect clipBounds) { |
| 127 return new TessellatingPathBatch(color, path, style, viewMatrix, clipBou
nds); | 125 return new TessellatingPathBatch(color, shape, viewMatrix, clipBounds); |
| 128 } | 126 } |
| 129 | 127 |
| 130 const char* name() const override { return "TessellatingPathBatch"; } | 128 const char* name() const override { return "TessellatingPathBatch"; } |
| 131 | 129 |
| 132 void computePipelineOptimizations(GrInitInvariantOutput* color, | 130 void computePipelineOptimizations(GrInitInvariantOutput* color, |
| 133 GrInitInvariantOutput* coverage, | 131 GrInitInvariantOutput* coverage, |
| 134 GrBatchToXPOverrides* overrides) const ove
rride { | 132 GrBatchToXPOverrides* overrides) const ove
rride { |
| 135 color->setKnownFourComponents(fColor); | 133 color->setKnownFourComponents(fColor); |
| 136 coverage->setUnknownSingleComponent(); | 134 coverage->setUnknownSingleComponent(); |
| 137 } | 135 } |
| 138 | 136 |
| 139 private: | 137 private: |
| 140 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { | 138 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { |
| 141 // Handle any color overrides | 139 // Handle any color overrides |
| 142 if (!overrides.readsColor()) { | 140 if (!overrides.readsColor()) { |
| 143 fColor = GrColor_ILLEGAL; | 141 fColor = GrColor_ILLEGAL; |
| 144 } | 142 } |
| 145 overrides.getOverrideColorIfSet(&fColor); | 143 overrides.getOverrideColorIfSet(&fColor); |
| 146 fPipelineInfo = overrides; | 144 fPipelineInfo = overrides; |
| 147 } | 145 } |
| 148 | 146 |
| 149 void draw(Target* target, const GrGeometryProcessor* gp) const { | 147 void draw(Target* target, const GrGeometryProcessor* gp) const { |
| 150 GrResourceProvider* rp = target->resourceProvider(); | 148 GrResourceProvider* rp = target->resourceProvider(); |
| 151 SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance; | 149 SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance; |
| 152 SkScalar tol = GrPathUtils::scaleToleranceToSrc(screenSpaceTol, fViewMat
rix, | 150 SkScalar tol = GrPathUtils::scaleToleranceToSrc(screenSpaceTol, fViewMat
rix, |
| 153 fPath.getBounds()); | 151 fShape.bounds()); |
| 154 | 152 |
| 155 SkScalar styleScale = SK_Scalar1; | 153 SkPath path; |
| 156 if (fStyle.applies()) { | 154 fShape.asPath(&path); |
| 157 styleScale = GrStyle::MatrixToScaleFactor(fViewMatrix); | 155 bool inverseFill = path.isInverseFillType(); |
| 158 } | |
| 159 | |
| 160 // construct a cache key from the path's genID and the view matrix | 156 // construct a cache key from the path's genID and the view matrix |
| 161 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain()
; | 157 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain()
; |
| 162 GrUniqueKey key; | 158 GrUniqueKey key; |
| 163 int clipBoundsCnt = | 159 static constexpr int kClipBoundsCnt = sizeof(fClipBounds) / sizeof(uint3
2_t); |
| 164 fPath.isInverseFillType() ? sizeof(fClipBounds) / sizeof(uint32_t) :
0; | 160 int shapeKeyDataCnt = fShape.unstyledKeySize(); |
| 165 int styleDataCnt = GrStyle::KeySize(fStyle, GrStyle::Apply::kPathEffectA
ndStrokeRec); | 161 SkASSERT(shapeKeyDataCnt >= 0); |
| 166 if (styleDataCnt >= 0) { | 162 GrUniqueKey::Builder builder(&key, kDomain, shapeKeyDataCnt + kClipBound
sCnt); |
| 167 GrUniqueKey::Builder builder(&key, kDomain, 2 + clipBoundsCnt + styl
eDataCnt); | 163 fShape.writeUnstyledKey(&builder[0]); |
| 168 builder[0] = fPath.getGenerationID(); | 164 // For inverse fills, the tessellation is dependent on clip bounds. |
| 169 builder[1] = fPath.getFillType(); | 165 if (inverseFill) { |
| 170 // For inverse fills, the tessellation is dependent on clip bounds. | 166 memcpy(&builder[shapeKeyDataCnt], &fClipBounds, sizeof(fClipBounds))
; |
| 171 if (fPath.isInverseFillType()) { | 167 } else { |
| 172 memcpy(&builder[2], &fClipBounds, sizeof(fClipBounds)); | 168 memset(&builder[shapeKeyDataCnt], 0, sizeof(fClipBounds)); |
| 173 } | 169 } |
| 174 if (styleDataCnt) { | 170 builder.finish(); |
| 175 GrStyle::WriteKey(&builder[2 + clipBoundsCnt], fStyle, | 171 SkAutoTUnref<GrBuffer> cachedVertexBuffer(rp->findAndRefTByUniqueKey<GrB
uffer>(key)); |
| 176 GrStyle::Apply::kPathEffectAndStrokeRec, style
Scale); | 172 int actualCount; |
| 177 } | 173 if (cache_match(cachedVertexBuffer.get(), tol, &actualCount)) { |
| 178 builder.finish(); | 174 this->drawVertices(target, gp, cachedVertexBuffer.get(), 0, actualCo
unt); |
| 179 SkAutoTUnref<GrBuffer> cachedVertexBuffer(rp->findAndRefTByUniqueKey
<GrBuffer>(key)); | 175 return; |
| 180 int actualCount; | |
| 181 if (cache_match(cachedVertexBuffer.get(), tol, &actualCount)) { | |
| 182 this->drawVertices(target, gp, cachedVertexBuffer.get(), 0, actu
alCount); | |
| 183 return; | |
| 184 } | |
| 185 } | 176 } |
| 186 | 177 |
| 187 SkPath path; | |
| 188 if (fStyle.applies()) { | |
| 189 SkStrokeRec::InitStyle fill; | |
| 190 SkAssertResult(fStyle.applyToPath(&path, &fill, fPath, styleScale)); | |
| 191 SkASSERT(SkStrokeRec::kFill_InitStyle == fill); | |
| 192 } else { | |
| 193 path = fPath; | |
| 194 } | |
| 195 bool isLinear; | 178 bool isLinear; |
| 196 bool canMapVB = GrCaps::kNone_MapFlags != target->caps().mapBufferFlags(
); | 179 bool canMapVB = GrCaps::kNone_MapFlags != target->caps().mapBufferFlags(
); |
| 197 StaticVertexAllocator allocator(rp, canMapVB); | 180 StaticVertexAllocator allocator(rp, canMapVB); |
| 198 int count = GrTessellator::PathToTriangles(path, tol, fClipBounds, &allo
cator, &isLinear); | 181 int count = GrTessellator::PathToTriangles(path, tol, fClipBounds, &allo
cator, &isLinear); |
| 199 if (count == 0) { | 182 if (count == 0) { |
| 200 return; | 183 return; |
| 201 } | 184 } |
| 202 this->drawVertices(target, gp, allocator.vertexBuffer(), 0, count); | 185 this->drawVertices(target, gp, allocator.vertexBuffer(), 0, count); |
| 203 if (!fPath.isVolatile() && styleDataCnt >= 0) { | 186 TessInfo info; |
| 204 TessInfo info; | 187 info.fTolerance = isLinear ? 0 : tol; |
| 205 info.fTolerance = isLinear ? 0 : tol; | 188 info.fCount = count; |
| 206 info.fCount = count; | 189 SkAutoTUnref<SkData> data(SkData::NewWithCopy(&info, sizeof(info))); |
| 207 SkAutoTUnref<SkData> data(SkData::NewWithCopy(&info, sizeof(info))); | 190 key.setCustomData(data.get()); |
| 208 key.setCustomData(data.get()); | 191 rp->assignUniqueKeyToResource(key, allocator.vertexBuffer()); |
| 209 rp->assignUniqueKeyToResource(key, allocator.vertexBuffer()); | |
| 210 SkPathPriv::AddGenIDChangeListener(fPath, new PathInvalidator(key)); | |
| 211 } | |
| 212 } | 192 } |
| 213 | 193 |
| 214 void onPrepareDraws(Target* target) const override { | 194 void onPrepareDraws(Target* target) const override { |
| 215 sk_sp<GrGeometryProcessor> gp; | 195 sk_sp<GrGeometryProcessor> gp; |
| 216 { | 196 { |
| 217 using namespace GrDefaultGeoProcFactory; | 197 using namespace GrDefaultGeoProcFactory; |
| 218 | 198 |
| 219 Color color(fColor); | 199 Color color(fColor); |
| 220 LocalCoords localCoords(fPipelineInfo.readsLocalCoords() ? | 200 LocalCoords localCoords(fPipelineInfo.readsLocalCoords() ? |
| 221 LocalCoords::kUsePosition_Type : | 201 LocalCoords::kUsePosition_Type : |
| (...skipping 17 matching lines...) Expand all Loading... |
| 239 GrPrimitiveType primitiveType = TESSELLATOR_WIREFRAME ? kLines_GrPrimiti
veType | 219 GrPrimitiveType primitiveType = TESSELLATOR_WIREFRAME ? kLines_GrPrimiti
veType |
| 240 : kTriangles_GrPri
mitiveType; | 220 : kTriangles_GrPri
mitiveType; |
| 241 GrMesh mesh; | 221 GrMesh mesh; |
| 242 mesh.init(primitiveType, vb, firstVertex, count); | 222 mesh.init(primitiveType, vb, firstVertex, count); |
| 243 target->draw(gp, mesh); | 223 target->draw(gp, mesh); |
| 244 } | 224 } |
| 245 | 225 |
| 246 bool onCombineIfPossible(GrBatch*, const GrCaps&) override { return false; } | 226 bool onCombineIfPossible(GrBatch*, const GrCaps&) override { return false; } |
| 247 | 227 |
| 248 TessellatingPathBatch(const GrColor& color, | 228 TessellatingPathBatch(const GrColor& color, |
| 249 const SkPath& path, | 229 const GrShape& shape, |
| 250 const GrStyle& style, | |
| 251 const SkMatrix& viewMatrix, | 230 const SkMatrix& viewMatrix, |
| 252 const SkRect& clipBounds) | 231 const SkRect& clipBounds) |
| 253 : INHERITED(ClassID()) | 232 : INHERITED(ClassID()) |
| 254 , fColor(color) | 233 , fColor(color) |
| 255 , fPath(path) | 234 , fShape(shape) |
| 256 , fStyle(style) | |
| 257 , fViewMatrix(viewMatrix) { | 235 , fViewMatrix(viewMatrix) { |
| 258 const SkRect& pathBounds = path.getBounds(); | 236 const SkRect& pathBounds = shape.bounds(); |
| 259 fClipBounds = clipBounds; | 237 fClipBounds = clipBounds; |
| 260 // Because the clip bounds are used to add a contour for inverse fills,
they must also | 238 // Because the clip bounds are used to add a contour for inverse fills,
they must also |
| 261 // include the path bounds. | 239 // include the path bounds. |
| 262 fClipBounds.join(pathBounds); | 240 fClipBounds.join(pathBounds); |
| 263 if (path.isInverseFillType()) { | 241 if (shape.inverseFilled()) { |
| 264 fBounds = fClipBounds; | 242 fBounds = fClipBounds; |
| 265 } else { | 243 } else { |
| 266 fBounds = path.getBounds(); | 244 fBounds = pathBounds; |
| 267 } | 245 } |
| 268 style.adjustBounds(&fBounds, fBounds); | |
| 269 viewMatrix.mapRect(&fBounds); | 246 viewMatrix.mapRect(&fBounds); |
| 270 } | 247 } |
| 271 | 248 |
| 272 GrColor fColor; | 249 GrColor fColor; |
| 273 SkPath fPath; | 250 GrShape fShape; |
| 274 GrStyle fStyle; | |
| 275 SkMatrix fViewMatrix; | 251 SkMatrix fViewMatrix; |
| 276 SkRect fClipBounds; // in source space | 252 SkRect fClipBounds; // in source space |
| 277 GrXPOverridesForBatch fPipelineInfo; | 253 GrXPOverridesForBatch fPipelineInfo; |
| 278 | 254 |
| 279 typedef GrVertexBatch INHERITED; | 255 typedef GrVertexBatch INHERITED; |
| 280 }; | 256 }; |
| 281 | 257 |
| 282 bool GrTessellatingPathRenderer::onDrawPath(const DrawPathArgs& args) { | 258 bool GrTessellatingPathRenderer::onDrawPath(const DrawPathArgs& args) { |
| 283 GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(), | 259 GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(), |
| 284 "GrTessellatingPathRenderer::onDrawPath"); | 260 "GrTessellatingPathRenderer::onDrawPath"); |
| 285 SkASSERT(!args.fAntiAlias); | 261 SkASSERT(!args.fAntiAlias); |
| 286 | 262 |
| 287 SkIRect clipBoundsI; | 263 SkIRect clipBoundsI; |
| 288 args.fClip->getConservativeBounds(args.fDrawContext->width(), args.fDrawCont
ext->height(), | 264 args.fClip->getConservativeBounds(args.fDrawContext->width(), args.fDrawCont
ext->height(), |
| 289 &clipBoundsI); | 265 &clipBoundsI); |
| 290 SkRect clipBounds = SkRect::Make(clipBoundsI); | 266 SkRect clipBounds = SkRect::Make(clipBoundsI); |
| 291 SkMatrix vmi; | 267 SkMatrix vmi; |
| 292 if (!args.fViewMatrix->invert(&vmi)) { | 268 if (!args.fViewMatrix->invert(&vmi)) { |
| 293 return false; | 269 return false; |
| 294 } | 270 } |
| 295 vmi.mapRect(&clipBounds); | 271 vmi.mapRect(&clipBounds); |
| 296 SkPath path; | 272 SkPath path; |
| 297 args.fShape->asPath(&path); | 273 args.fShape->asPath(&path); |
| 298 SkAutoTUnref<GrDrawBatch> batch(TessellatingPathBatch::Create(args.fColor, p
ath, | 274 SkAutoTUnref<GrDrawBatch> batch(TessellatingPathBatch::Create(args.fColor, *
args.fShape, |
| 299 args.fShape->s
tyle(), | 275 *args.fViewMat
rix, clipBounds)); |
| 300 *args.fViewMat
rix, | |
| 301 clipBounds)); | |
| 302 | 276 |
| 303 GrPipelineBuilder pipelineBuilder(*args.fPaint, args.fDrawContext->mustUseHW
AA(*args.fPaint)); | 277 GrPipelineBuilder pipelineBuilder(*args.fPaint, args.fDrawContext->mustUseHW
AA(*args.fPaint)); |
| 304 pipelineBuilder.setUserStencil(args.fUserStencilSettings); | 278 pipelineBuilder.setUserStencil(args.fUserStencilSettings); |
| 305 | 279 |
| 306 args.fDrawContext->drawBatch(pipelineBuilder, *args.fClip, batch); | 280 args.fDrawContext->drawBatch(pipelineBuilder, *args.fClip, batch); |
| 307 | 281 |
| 308 return true; | 282 return true; |
| 309 } | 283 } |
| 310 | 284 |
| 311 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 285 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
| 312 | 286 |
| 313 #ifdef GR_TEST_UTILS | 287 #ifdef GR_TEST_UTILS |
| 314 | 288 |
| 315 DRAW_BATCH_TEST_DEFINE(TesselatingPathBatch) { | 289 DRAW_BATCH_TEST_DEFINE(TesselatingPathBatch) { |
| 316 GrColor color = GrRandomColor(random); | 290 GrColor color = GrRandomColor(random); |
| 317 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random); | 291 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random); |
| 318 SkPath path = GrTest::TestPath(random); | 292 SkPath path = GrTest::TestPath(random); |
| 319 SkRect clipBounds = GrTest::TestRect(random); | 293 SkRect clipBounds = GrTest::TestRect(random); |
| 320 SkMatrix vmi; | 294 SkMatrix vmi; |
| 321 bool result = viewMatrix.invert(&vmi); | 295 bool result = viewMatrix.invert(&vmi); |
| 322 if (!result) { | 296 if (!result) { |
| 323 SkFAIL("Cannot invert matrix\n"); | 297 SkFAIL("Cannot invert matrix\n"); |
| 324 } | 298 } |
| 325 vmi.mapRect(&clipBounds); | 299 vmi.mapRect(&clipBounds); |
| 326 GrStyle style; | 300 GrStyle style; |
| 327 do { | 301 do { |
| 328 GrTest::TestStyle(random, &style); | 302 GrTest::TestStyle(random, &style); |
| 329 } while (style.strokeRec().isHairlineStyle()); | 303 } while (style.strokeRec().isHairlineStyle()); |
| 330 return TessellatingPathBatch::Create(color, path, style, viewMatrix, clipBou
nds); | 304 GrShape shape(path, style); |
| 305 return TessellatingPathBatch::Create(color, shape, viewMatrix, clipBounds); |
| 331 } | 306 } |
| 332 | 307 |
| 333 #endif | 308 #endif |
| OLD | NEW |