Chromium Code Reviews| 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 "GrBatchFlushState.h" | 10 #include "GrBatchFlushState.h" |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 98 }; | 98 }; |
| 99 | 99 |
| 100 } // namespace | 100 } // namespace |
| 101 | 101 |
| 102 GrTessellatingPathRenderer::GrTessellatingPathRenderer() { | 102 GrTessellatingPathRenderer::GrTessellatingPathRenderer() { |
| 103 } | 103 } |
| 104 | 104 |
| 105 bool GrTessellatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) cons t { | 105 bool GrTessellatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) cons t { |
| 106 // This path renderer can draw all fill styles, all stroke styles except hai rlines, but does | 106 // This path renderer can draw all fill styles, all stroke styles except hai rlines, but does |
| 107 // not do antialiasing. It can do convex and concave paths, but we'll leave the convex ones to | 107 // not do antialiasing. It can do convex and concave paths, but we'll leave the convex ones to |
| 108 // simpler algorithms. | 108 // simpler algorithms. Similary, we skip the non-hairlines that can be treat ed as hairline. |
| 109 return !IsStrokeHairlineOrEquivalent(*args.fStroke, *args.fViewMatrix, nullp tr) && | 109 // An arbitrary path effect could produce a hairline result so we pass on th ose. |
| 110 !args.fAntiAlias && !args.fPath->isConvex(); | 110 return !IsStrokeHairlineOrEquivalent(*args.fStyle, *args.fViewMatrix, nullpt r) && |
| 111 !args.fStyle->hasNonDashPathEffect() && !args.fAntiAlias && !args.fPa th->isConvex(); | |
| 111 } | 112 } |
| 112 | 113 |
| 113 class TessellatingPathBatch : public GrVertexBatch { | 114 class TessellatingPathBatch : public GrVertexBatch { |
| 114 public: | 115 public: |
| 115 DEFINE_BATCH_CLASS_ID | 116 DEFINE_BATCH_CLASS_ID |
| 116 | 117 |
| 117 static GrDrawBatch* Create(const GrColor& color, | 118 static GrDrawBatch* Create(const GrColor& color, |
| 118 const SkPath& path, | 119 const SkPath& path, |
| 119 const GrStrokeInfo& stroke, | 120 const GrStyle& style, |
| 120 const SkMatrix& viewMatrix, | 121 const SkMatrix& viewMatrix, |
| 121 SkRect clipBounds) { | 122 SkRect clipBounds) { |
| 122 return new TessellatingPathBatch(color, path, stroke, viewMatrix, clipBo unds); | 123 return new TessellatingPathBatch(color, path, style, viewMatrix, clipBou nds); |
| 123 } | 124 } |
| 124 | 125 |
| 125 const char* name() const override { return "TessellatingPathBatch"; } | 126 const char* name() const override { return "TessellatingPathBatch"; } |
| 126 | 127 |
| 127 void computePipelineOptimizations(GrInitInvariantOutput* color, | 128 void computePipelineOptimizations(GrInitInvariantOutput* color, |
| 128 GrInitInvariantOutput* coverage, | 129 GrInitInvariantOutput* coverage, |
| 129 GrBatchToXPOverrides* overrides) const ove rride { | 130 GrBatchToXPOverrides* overrides) const ove rride { |
| 130 color->setKnownFourComponents(fColor); | 131 color->setKnownFourComponents(fColor); |
| 131 coverage->setUnknownSingleComponent(); | 132 coverage->setUnknownSingleComponent(); |
| 132 } | 133 } |
| 133 | 134 |
| 134 private: | 135 private: |
| 135 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { | 136 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { |
| 136 // Handle any color overrides | 137 // Handle any color overrides |
| 137 if (!overrides.readsColor()) { | 138 if (!overrides.readsColor()) { |
| 138 fColor = GrColor_ILLEGAL; | 139 fColor = GrColor_ILLEGAL; |
| 139 } | 140 } |
| 140 overrides.getOverrideColorIfSet(&fColor); | 141 overrides.getOverrideColorIfSet(&fColor); |
| 141 fPipelineInfo = overrides; | 142 fPipelineInfo = overrides; |
| 142 } | 143 } |
| 143 | 144 |
| 144 void draw(Target* target, const GrGeometryProcessor* gp) const { | 145 void draw(Target* target, const GrGeometryProcessor* gp) const { |
| 146 GrResourceProvider* rp = target->resourceProvider(); | |
| 147 SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance; | |
| 148 SkScalar tol = GrPathUtils::scaleToleranceToSrc(screenSpaceTol, fViewMat rix, | |
| 149 fPath.getBounds()); | |
| 150 | |
| 151 SkScalar styleScale = SK_Scalar1; | |
| 152 if (fStyle.applies()) { | |
| 153 styleScale = GrStyle::MatrixToScaleFactor(fViewMatrix); | |
|
robertphillips
2016/05/09 20:05:28
stray ';' ?
bsalomon
2016/05/09 20:38:55
Done.
| |
| 154 }; | |
| 155 | |
| 145 // 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 |
| 146 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain() ; | 157 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain() ; |
| 147 GrUniqueKey key; | 158 GrUniqueKey key; |
| 148 int clipBoundsSize32 = | 159 int clipBoundsSize32 = |
| 149 fPath.isInverseFillType() ? sizeof(fClipBounds) / sizeof(uint32_t) : 0; | 160 fPath.isInverseFillType() ? sizeof(fClipBounds) / sizeof(uint32_t) : 0; |
|
robertphillips
2016/05/09 20:05:28
can we rm the 32 suffix ?
bsalomon
2016/05/09 20:38:55
Done.
| |
| 150 int strokeDataSize32 = fStroke.computeUniqueKeyFragmentData32Cnt(); | 161 int styleDataSize32 = GrStyle::KeySize(fStyle, GrStyle::Apply::kPathEffe ctAndStrokeRec); |
| 151 GrUniqueKey::Builder builder(&key, kDomain, 2 + clipBoundsSize32 + strok eDataSize32); | 162 if (styleDataSize32 >= 0) { |
| 152 builder[0] = fPath.getGenerationID(); | 163 GrUniqueKey::Builder builder(&key, kDomain, 2 + clipBoundsSize32 + s tyleDataSize32); |
| 153 builder[1] = fPath.getFillType(); | 164 builder[0] = fPath.getGenerationID(); |
| 154 // For inverse fills, the tessellation is dependent on clip bounds. | 165 builder[1] = fPath.getFillType(); |
| 155 if (fPath.isInverseFillType()) { | 166 // For inverse fills, the tessellation is dependent on clip bounds. |
| 156 memcpy(&builder[2], &fClipBounds, sizeof(fClipBounds)); | 167 if (fPath.isInverseFillType()) { |
| 157 } | 168 memcpy(&builder[2], &fClipBounds, sizeof(fClipBounds)); |
| 158 fStroke.asUniqueKeyFragment(&builder[2 + clipBoundsSize32]); | 169 } |
| 159 builder.finish(); | 170 if (styleDataSize32) { |
| 160 GrResourceProvider* rp = target->resourceProvider(); | 171 GrStyle::WriteKey(&builder[2 + clipBoundsSize32], fStyle, |
| 161 SkAutoTUnref<GrBuffer> cachedVertexBuffer(rp->findAndRefTByUniqueKey<GrB uffer>(key)); | 172 GrStyle::Apply::kPathEffectAndStrokeRec, style Scale); |
| 162 int actualCount; | 173 } |
| 163 SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance; | 174 builder.finish(); |
| 164 SkScalar tol = GrPathUtils::scaleToleranceToSrc( | 175 SkAutoTUnref<GrBuffer> cachedVertexBuffer(rp->findAndRefTByUniqueKey <GrBuffer>(key)); |
| 165 screenSpaceTol, fViewMatrix, fPath.getBounds()); | 176 int actualCount; |
| 166 if (cache_match(cachedVertexBuffer.get(), tol, &actualCount)) { | 177 if (cache_match(cachedVertexBuffer.get(), tol, &actualCount)) { |
| 167 this->drawVertices(target, gp, cachedVertexBuffer.get(), 0, actualCo unt); | 178 this->drawVertices(target, gp, cachedVertexBuffer.get(), 0, actu alCount); |
| 168 return; | 179 return; |
| 180 } | |
| 169 } | 181 } |
| 170 | 182 |
| 171 SkPath path; | 183 SkPath path; |
| 172 GrStrokeInfo stroke(fStroke); | 184 if (fStyle.applies()) { |
| 173 if (stroke.isDashed()) { | 185 SkStrokeRec::InitStyle fill; |
| 174 if (!stroke.applyDashToPath(&path, &stroke, fPath)) { | 186 SkAssertResult(fStyle.applyToPath(&path, &fill, fPath, styleScale)); |
| 175 return; | 187 SkASSERT(SkStrokeRec::kFill_InitStyle == fill); |
| 176 } | |
| 177 } else { | 188 } else { |
| 178 path = fPath; | 189 path = fPath; |
| 179 } | 190 } |
| 180 if (!stroke.isFillStyle()) { | |
| 181 stroke.setResScale(SkScalarAbs(fViewMatrix.getMaxScale())); | |
| 182 if (!stroke.applyToPath(&path, path)) { | |
| 183 return; | |
| 184 } | |
| 185 stroke.setFillStyle(); | |
| 186 } | |
| 187 bool isLinear; | 191 bool isLinear; |
| 188 bool canMapVB = GrCaps::kNone_MapFlags != target->caps().mapBufferFlags( ); | 192 bool canMapVB = GrCaps::kNone_MapFlags != target->caps().mapBufferFlags( ); |
| 189 StaticVertexAllocator allocator(rp, canMapVB); | 193 StaticVertexAllocator allocator(rp, canMapVB); |
| 190 int count = GrTessellator::PathToTriangles(path, tol, fClipBounds, &allo cator, &isLinear); | 194 int count = GrTessellator::PathToTriangles(path, tol, fClipBounds, &allo cator, &isLinear); |
| 191 if (count == 0) { | 195 if (count == 0) { |
| 192 return; | 196 return; |
| 193 } | 197 } |
| 194 this->drawVertices(target, gp, allocator.vertexBuffer(), 0, count); | 198 this->drawVertices(target, gp, allocator.vertexBuffer(), 0, count); |
| 195 if (!fPath.isVolatile()) { | 199 if (!fPath.isVolatile() && styleDataSize32 >= 0) { |
| 196 TessInfo info; | 200 TessInfo info; |
| 197 info.fTolerance = isLinear ? 0 : tol; | 201 info.fTolerance = isLinear ? 0 : tol; |
| 198 info.fCount = count; | 202 info.fCount = count; |
| 199 SkAutoTUnref<SkData> data(SkData::NewWithCopy(&info, sizeof(info))); | 203 SkAutoTUnref<SkData> data(SkData::NewWithCopy(&info, sizeof(info))); |
| 200 key.setCustomData(data.get()); | 204 key.setCustomData(data.get()); |
| 201 rp->assignUniqueKeyToResource(key, allocator.vertexBuffer()); | 205 rp->assignUniqueKeyToResource(key, allocator.vertexBuffer()); |
| 202 SkPathPriv::AddGenIDChangeListener(fPath, new PathInvalidator(key)); | 206 SkPathPriv::AddGenIDChangeListener(fPath, new PathInvalidator(key)); |
| 203 } | 207 } |
| 204 } | 208 } |
| 205 | 209 |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 233 : kTriangles_GrPri mitiveType; | 237 : kTriangles_GrPri mitiveType; |
| 234 GrMesh mesh; | 238 GrMesh mesh; |
| 235 mesh.init(primitiveType, vb, firstVertex, count); | 239 mesh.init(primitiveType, vb, firstVertex, count); |
| 236 target->draw(gp, mesh); | 240 target->draw(gp, mesh); |
| 237 } | 241 } |
| 238 | 242 |
| 239 bool onCombineIfPossible(GrBatch*, const GrCaps&) override { return false; } | 243 bool onCombineIfPossible(GrBatch*, const GrCaps&) override { return false; } |
| 240 | 244 |
| 241 TessellatingPathBatch(const GrColor& color, | 245 TessellatingPathBatch(const GrColor& color, |
| 242 const SkPath& path, | 246 const SkPath& path, |
| 243 const GrStrokeInfo& stroke, | 247 const GrStyle& style, |
| 244 const SkMatrix& viewMatrix, | 248 const SkMatrix& viewMatrix, |
| 245 const SkRect& clipBounds) | 249 const SkRect& clipBounds) |
| 246 : INHERITED(ClassID()) | 250 : INHERITED(ClassID()) |
| 247 , fColor(color) | 251 , fColor(color) |
| 248 , fPath(path) | 252 , fPath(path) |
| 249 , fStroke(stroke) | 253 , fStyle(style) |
| 250 , fViewMatrix(viewMatrix) { | 254 , fViewMatrix(viewMatrix) { |
| 251 const SkRect& pathBounds = path.getBounds(); | 255 const SkRect& pathBounds = path.getBounds(); |
| 252 fClipBounds = clipBounds; | 256 fClipBounds = clipBounds; |
| 253 // Because the clip bounds are used to add a contour for inverse fills, they must also | 257 // Because the clip bounds are used to add a contour for inverse fills, they must also |
| 254 // include the path bounds. | 258 // include the path bounds. |
| 255 fClipBounds.join(pathBounds); | 259 fClipBounds.join(pathBounds); |
| 256 if (path.isInverseFillType()) { | 260 if (path.isInverseFillType()) { |
| 257 fBounds = fClipBounds; | 261 fBounds = fClipBounds; |
| 258 } else { | 262 } else { |
| 259 fBounds = path.getBounds(); | 263 fBounds = path.getBounds(); |
| 260 } | 264 } |
| 261 SkScalar radius = stroke.getInflationRadius(); | 265 style.adjustBounds(&fBounds, fBounds); |
| 262 fBounds.outset(radius, radius); | |
| 263 viewMatrix.mapRect(&fBounds); | 266 viewMatrix.mapRect(&fBounds); |
| 264 } | 267 } |
| 265 | 268 |
| 266 GrColor fColor; | 269 GrColor fColor; |
| 267 SkPath fPath; | 270 SkPath fPath; |
| 268 GrStrokeInfo fStroke; | 271 GrStyle fStyle; |
| 269 SkMatrix fViewMatrix; | 272 SkMatrix fViewMatrix; |
| 270 SkRect fClipBounds; // in source space | 273 SkRect fClipBounds; // in source space |
| 271 GrXPOverridesForBatch fPipelineInfo; | 274 GrXPOverridesForBatch fPipelineInfo; |
| 272 | 275 |
| 273 typedef GrVertexBatch INHERITED; | 276 typedef GrVertexBatch INHERITED; |
| 274 }; | 277 }; |
| 275 | 278 |
| 276 bool GrTessellatingPathRenderer::onDrawPath(const DrawPathArgs& args) { | 279 bool GrTessellatingPathRenderer::onDrawPath(const DrawPathArgs& args) { |
| 277 GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(), | 280 GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(), |
| 278 "GrTessellatingPathRenderer::onDrawPath"); | 281 "GrTessellatingPathRenderer::onDrawPath"); |
| 279 SkASSERT(!args.fAntiAlias); | 282 SkASSERT(!args.fAntiAlias); |
| 280 const GrRenderTarget* rt = args.fPipelineBuilder->getRenderTarget(); | 283 const GrRenderTarget* rt = args.fPipelineBuilder->getRenderTarget(); |
| 281 if (nullptr == rt) { | 284 if (nullptr == rt) { |
| 282 return false; | 285 return false; |
| 283 } | 286 } |
| 284 | 287 |
| 285 SkIRect clipBoundsI; | 288 SkIRect clipBoundsI; |
| 286 args.fPipelineBuilder->clip().getConservativeBounds(rt->width(), rt->height( ), &clipBoundsI); | 289 args.fPipelineBuilder->clip().getConservativeBounds(rt->width(), rt->height( ), &clipBoundsI); |
| 287 SkRect clipBounds = SkRect::Make(clipBoundsI); | 290 SkRect clipBounds = SkRect::Make(clipBoundsI); |
| 288 SkMatrix vmi; | 291 SkMatrix vmi; |
| 289 if (!args.fViewMatrix->invert(&vmi)) { | 292 if (!args.fViewMatrix->invert(&vmi)) { |
| 290 return false; | 293 return false; |
| 291 } | 294 } |
| 292 vmi.mapRect(&clipBounds); | 295 vmi.mapRect(&clipBounds); |
| 293 SkAutoTUnref<GrDrawBatch> batch(TessellatingPathBatch::Create(args.fColor, * args.fPath, | 296 SkAutoTUnref<GrDrawBatch> batch(TessellatingPathBatch::Create(args.fColor, * args.fPath, |
| 294 *args.fStroke, *args.fViewMatrix, | 297 *args.fStyle, *args.fViewMatrix, |
| 295 clipBounds)); | 298 clipBounds)); |
| 296 args.fTarget->drawBatch(*args.fPipelineBuilder, batch); | 299 args.fTarget->drawBatch(*args.fPipelineBuilder, batch); |
| 297 | 300 |
| 298 return true; | 301 return true; |
| 299 } | 302 } |
| 300 | 303 |
| 301 //////////////////////////////////////////////////////////////////////////////// /////////////////// | 304 //////////////////////////////////////////////////////////////////////////////// /////////////////// |
| 302 | 305 |
| 303 #ifdef GR_TEST_UTILS | 306 #ifdef GR_TEST_UTILS |
| 304 | 307 |
| 305 DRAW_BATCH_TEST_DEFINE(TesselatingPathBatch) { | 308 DRAW_BATCH_TEST_DEFINE(TesselatingPathBatch) { |
| 306 GrColor color = GrRandomColor(random); | 309 GrColor color = GrRandomColor(random); |
| 307 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random); | 310 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random); |
| 308 SkPath path = GrTest::TestPath(random); | 311 SkPath path = GrTest::TestPath(random); |
| 309 SkRect clipBounds = GrTest::TestRect(random); | 312 SkRect clipBounds = GrTest::TestRect(random); |
| 310 SkMatrix vmi; | 313 SkMatrix vmi; |
| 311 bool result = viewMatrix.invert(&vmi); | 314 bool result = viewMatrix.invert(&vmi); |
| 312 if (!result) { | 315 if (!result) { |
| 313 SkFAIL("Cannot invert matrix\n"); | 316 SkFAIL("Cannot invert matrix\n"); |
| 314 } | 317 } |
| 315 vmi.mapRect(&clipBounds); | 318 vmi.mapRect(&clipBounds); |
| 316 GrStrokeInfo strokeInfo = GrTest::TestStrokeInfo(random); | 319 GrStyle style; |
| 317 return TessellatingPathBatch::Create(color, path, strokeInfo, viewMatrix, cl ipBounds); | 320 do { |
| 321 GrTest::TestStyle(random, &style); | |
| 322 } while (style.strokeRec().isHairlineStyle()); | |
| 323 return TessellatingPathBatch::Create(color, path, style, viewMatrix, clipBou nds); | |
| 318 } | 324 } |
| 319 | 325 |
| 320 #endif | 326 #endif |
| OLD | NEW |