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 "GrAuditTrail.h" | 10 #include "GrAuditTrail.h" |
| 11 #include "GrBatchFlushState.h" | 11 #include "GrBatchFlushState.h" |
| 12 #include "GrBatchTest.h" | 12 #include "GrBatchTest.h" |
| 13 #include "GrClip.h" | 13 #include "GrClip.h" |
| 14 #include "GrDefaultGeoProcFactory.h" | 14 #include "GrDefaultGeoProcFactory.h" |
| 15 #include "GrDrawTarget.h" | |
| 15 #include "GrMesh.h" | 16 #include "GrMesh.h" |
| 16 #include "GrPathUtils.h" | 17 #include "GrPathUtils.h" |
| 17 #include "GrPipelineBuilder.h" | 18 #include "GrPipelineBuilder.h" |
| 18 #include "GrResourceCache.h" | 19 #include "GrResourceCache.h" |
| 19 #include "GrResourceProvider.h" | 20 #include "GrResourceProvider.h" |
| 20 #include "GrTessellator.h" | 21 #include "GrTessellator.h" |
| 21 #include "SkGeometry.h" | 22 #include "SkGeometry.h" |
| 22 | 23 |
| 23 #include "batches/GrVertexBatch.h" | 24 #include "batches/GrVertexBatch.h" |
| 24 | 25 |
| 25 #include <stdio.h> | 26 #include <stdio.h> |
| 26 | 27 |
| 28 #define SK_DISABLE_SCREENSPACE_TESS_AA_PATH_RENDERER | |
| 29 | |
| 27 /* | 30 /* |
| 28 * This path renderer tessellates the path into triangles using GrTessellator, u ploads the triangles | 31 * This path renderer tessellates the path into triangles using GrTessellator, u ploads the |
| 29 * to a vertex buffer, and renders them with a single draw call. It does not cur rently do | 32 * triangles to a vertex buffer, and renders them with a single draw call. It ca n do screenspace |
| 30 * antialiasing, so it must be used in conjunction with multisampling. | 33 * antialiasing with a one-pixel coverage ramp. |
| 31 */ | 34 */ |
| 32 namespace { | 35 namespace { |
| 33 | 36 |
| 34 struct TessInfo { | 37 struct TessInfo { |
| 35 SkScalar fTolerance; | 38 SkScalar fTolerance; |
| 36 int fCount; | 39 int fCount; |
| 37 }; | 40 }; |
| 38 | 41 |
| 39 // When the SkPathRef genID changes, invalidate a corresponding GrResource descr ibed by key. | 42 // When the SkPathRef genID changes, invalidate a corresponding GrResource descr ibed by key. |
| 40 class PathInvalidator : public SkPathRef::GenIDChangeListener { | 43 class PathInvalidator : public SkPathRef::GenIDChangeListener { |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 57 const TessInfo* info = static_cast<const TessInfo*>(data->data()); | 60 const TessInfo* info = static_cast<const TessInfo*>(data->data()); |
| 58 if (info->fTolerance == 0 || info->fTolerance < 3.0f * tol) { | 61 if (info->fTolerance == 0 || info->fTolerance < 3.0f * tol) { |
| 59 *actualCount = info->fCount; | 62 *actualCount = info->fCount; |
| 60 return true; | 63 return true; |
| 61 } | 64 } |
| 62 return false; | 65 return false; |
| 63 } | 66 } |
| 64 | 67 |
| 65 class StaticVertexAllocator : public GrTessellator::VertexAllocator { | 68 class StaticVertexAllocator : public GrTessellator::VertexAllocator { |
| 66 public: | 69 public: |
| 67 StaticVertexAllocator(GrResourceProvider* resourceProvider, bool canMapVB) | 70 StaticVertexAllocator(size_t stride, GrResourceProvider* resourceProvider, b ool canMapVB) |
| 68 : fResourceProvider(resourceProvider) | 71 : VertexAllocator(stride) |
| 72 , fResourceProvider(resourceProvider) | |
| 69 , fCanMapVB(canMapVB) | 73 , fCanMapVB(canMapVB) |
| 70 , fVertices(nullptr) { | 74 , fVertices(nullptr) { |
| 71 } | 75 } |
| 72 SkPoint* lock(int vertexCount) override { | 76 void* lock(int vertexCount) override { |
| 73 size_t size = vertexCount * sizeof(SkPoint); | 77 size_t size = vertexCount * stride(); |
| 74 fVertexBuffer.reset(fResourceProvider->createBuffer( | 78 fVertexBuffer.reset(fResourceProvider->createBuffer( |
| 75 size, kVertex_GrBufferType, kStatic_GrAccessPattern, 0)); | 79 size, kVertex_GrBufferType, kStatic_GrAccessPattern, 0)); |
| 76 if (!fVertexBuffer.get()) { | 80 if (!fVertexBuffer.get()) { |
| 77 return nullptr; | 81 return nullptr; |
| 78 } | 82 } |
| 79 if (fCanMapVB) { | 83 if (fCanMapVB) { |
| 80 fVertices = static_cast<SkPoint*>(fVertexBuffer->map()); | 84 fVertices = fVertexBuffer->map(); |
| 81 } else { | 85 } else { |
| 82 fVertices = new SkPoint[vertexCount]; | 86 fVertices = sk_malloc_throw(vertexCount * stride()); |
| 83 } | 87 } |
| 84 return fVertices; | 88 return fVertices; |
| 85 } | 89 } |
| 86 void unlock(int actualCount) override { | 90 void unlock(int actualCount) override { |
| 87 if (fCanMapVB) { | 91 if (fCanMapVB) { |
| 88 fVertexBuffer->unmap(); | 92 fVertexBuffer->unmap(); |
| 89 } else { | 93 } else { |
| 90 fVertexBuffer->updateData(fVertices, actualCount * sizeof(SkPoint)); | 94 fVertexBuffer->updateData(fVertices, actualCount * stride()); |
| 91 delete[] fVertices; | 95 sk_free(fVertices); |
| 92 } | 96 } |
| 93 fVertices = nullptr; | 97 fVertices = nullptr; |
| 94 } | 98 } |
| 95 GrBuffer* vertexBuffer() { return fVertexBuffer.get(); } | 99 GrBuffer* vertexBuffer() { return fVertexBuffer.get(); } |
| 96 private: | 100 private: |
| 97 SkAutoTUnref<GrBuffer> fVertexBuffer; | 101 SkAutoTUnref<GrBuffer> fVertexBuffer; |
| 98 GrResourceProvider* fResourceProvider; | 102 GrResourceProvider* fResourceProvider; |
| 99 bool fCanMapVB; | 103 bool fCanMapVB; |
| 100 SkPoint* fVertices; | 104 void* fVertices; |
| 105 }; | |
| 106 | |
| 107 class DynamicVertexAllocator : public GrTessellator::VertexAllocator { | |
| 108 public: | |
| 109 DynamicVertexAllocator(size_t stride, GrVertexBatch::Target* target) | |
| 110 : VertexAllocator(stride) | |
| 111 , fTarget(target) | |
| 112 , fVertexBuffer(nullptr) | |
| 113 , fVertices(nullptr) { | |
| 114 } | |
| 115 void* lock(int vertexCount) override { | |
| 116 fVertexCount = vertexCount; | |
| 117 fVertices = fTarget->makeVertexSpace(stride(), vertexCount, &fVertexBuff er, &fFirstVertex); | |
| 118 return fVertices; | |
| 119 } | |
| 120 void unlock(int actualCount) override { | |
| 121 fTarget->putBackVertices(fVertexCount - actualCount, stride()); | |
| 122 fVertices = nullptr; | |
| 123 } | |
| 124 const GrBuffer* vertexBuffer() const { return fVertexBuffer; } | |
| 125 int firstVertex() const { return fFirstVertex; } | |
| 126 private: | |
| 127 GrVertexBatch::Target* fTarget; | |
| 128 const GrBuffer* fVertexBuffer; | |
| 129 int fVertexCount; | |
| 130 int fFirstVertex; | |
| 131 void* fVertices; | |
| 101 }; | 132 }; |
| 102 | 133 |
| 103 } // namespace | 134 } // namespace |
| 104 | 135 |
| 105 GrTessellatingPathRenderer::GrTessellatingPathRenderer() { | 136 GrTessellatingPathRenderer::GrTessellatingPathRenderer() { |
| 106 } | 137 } |
| 107 | 138 |
| 108 bool GrTessellatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) cons t { | 139 bool GrTessellatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) cons t { |
| 109 // This path renderer can draw fill styles but does not do antialiasing. It can do convex and | 140 // This path renderer can draw fill styles, and can do screenspace antialias ing via a |
| 110 // concave paths, but we'll leave the convex ones to simpler algorithms. We pass on paths that | 141 // one-pixel coverage ramp. It can do convex and concave paths, but we'll le ave the convex |
| 111 // have styles, though they may come back around after applying the styling information to the | 142 // ones to simpler algorithms. We pass on paths that have styles, though the y may come back |
| 112 // geometry to create a filled path. We also skip paths that don't have a ke y since the real | 143 // around after applying the styling information to the geometry to create a filled path. In |
| 113 // advantage of this path renderer comes from caching the tessellated geomet ry. | 144 // the non-AA case, We skip paths thta don't have a key since the real advan tage of this path |
| 145 // renderer comes from caching the tessellated geometry. In the AA case, we do not cache, so we | |
| 146 // accept paths without keys. | |
| 147 if (args.fAntiAlias) { | |
| 148 #ifdef SK_DISABLE_SCREENSPACE_TESS_AA_PATH_RENDERER | |
| 149 return false; | |
| 150 #else | |
| 151 SkPath path; | |
| 152 args.fShape->asPath(&path); | |
|
bsalomon
2016/08/31 14:19:19
If the path has a path effect or is stroked this o
Stephen White
2016/08/31 15:16:38
Good idea; done.
| |
| 153 if (path.countVerbs() > 10) { | |
| 154 return false; | |
| 155 } | |
| 156 #endif | |
| 157 } else if (!args.fShape->hasUnstyledKey()) { | |
| 158 return false; | |
| 159 } | |
| 114 return !args.fShape->style().applies() && args.fShape->style().isSimpleFill( ) && | 160 return !args.fShape->style().applies() && args.fShape->style().isSimpleFill( ) && |
|
bsalomon
2016/08/31 14:19:19
I realize that this is pre-existing (probably done
Stephen White
2016/08/31 15:16:38
Done.
| |
| 115 !args.fAntiAlias && args.fShape->hasUnstyledKey() && !args.fShape->kn ownToBeConvex(); | 161 !args.fShape->knownToBeConvex(); |
| 116 } | 162 } |
| 117 | 163 |
| 118 class TessellatingPathBatch : public GrVertexBatch { | 164 class TessellatingPathBatch : public GrVertexBatch { |
| 119 public: | 165 public: |
| 120 DEFINE_BATCH_CLASS_ID | 166 DEFINE_BATCH_CLASS_ID |
| 121 | 167 |
| 122 static GrDrawBatch* Create(const GrColor& color, | 168 static GrDrawBatch* Create(const GrColor& color, |
| 123 const GrShape& shape, | 169 const GrShape& shape, |
| 124 const SkMatrix& viewMatrix, | 170 const SkMatrix& viewMatrix, |
| 125 SkRect clipBounds) { | 171 SkIRect devClipBounds, |
| 126 return new TessellatingPathBatch(color, shape, viewMatrix, clipBounds); | 172 bool antiAlias) { |
| 173 return new TessellatingPathBatch(color, shape, viewMatrix, devClipBounds , antiAlias); | |
| 127 } | 174 } |
| 128 | 175 |
| 129 const char* name() const override { return "TessellatingPathBatch"; } | 176 const char* name() const override { return "TessellatingPathBatch"; } |
| 130 | 177 |
| 131 void computePipelineOptimizations(GrInitInvariantOutput* color, | 178 void computePipelineOptimizations(GrInitInvariantOutput* color, |
| 132 GrInitInvariantOutput* coverage, | 179 GrInitInvariantOutput* coverage, |
| 133 GrBatchToXPOverrides* overrides) const ove rride { | 180 GrBatchToXPOverrides* overrides) const ove rride { |
| 134 color->setKnownFourComponents(fColor); | 181 color->setKnownFourComponents(fColor); |
| 135 coverage->setUnknownSingleComponent(); | 182 coverage->setUnknownSingleComponent(); |
| 136 } | 183 } |
| 137 | 184 |
| 138 private: | 185 private: |
| 139 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { | 186 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { |
| 140 // Handle any color overrides | 187 // Handle any color overrides |
| 141 if (!overrides.readsColor()) { | 188 if (!overrides.readsColor()) { |
| 142 fColor = GrColor_ILLEGAL; | 189 fColor = GrColor_ILLEGAL; |
| 143 } | 190 } |
| 144 overrides.getOverrideColorIfSet(&fColor); | 191 overrides.getOverrideColorIfSet(&fColor); |
| 145 fPipelineInfo = overrides; | 192 fPipelineInfo = overrides; |
| 146 } | 193 } |
| 147 | 194 |
| 148 void draw(Target* target, const GrGeometryProcessor* gp) const { | 195 SkPath getPath() const { |
| 149 GrResourceProvider* rp = target->resourceProvider(); | |
| 150 SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance; | |
| 151 SkScalar tol = GrPathUtils::scaleToleranceToSrc(screenSpaceTol, fViewMat rix, | |
| 152 fShape.bounds()); | |
| 153 | |
| 154 SkPath path; | 196 SkPath path; |
|
bsalomon
2016/08/31 14:19:19
I think this can be:
fShape.applyStyle(GrStyle::Ap
Stephen White
2016/08/31 15:16:38
Actually, given that onCanDrawPath() checks that
!
bsalomon
2016/08/31 15:29:48
Agreed.
| |
| 155 fShape.asPath(&path); | 197 fShape.asPath(&path); |
| 156 bool inverseFill = path.isInverseFillType(); | 198 if (fShape.style().applies()) { |
| 199 SkScalar styleScale = GrStyle::MatrixToScaleFactor(fViewMatrix); | |
| 200 SkStrokeRec::InitStyle fill; | |
| 201 SkAssertResult(fShape.style().applyToPath(&path, &fill, path, styleS cale)); | |
| 202 SkASSERT(SkStrokeRec::kFill_InitStyle == fill); | |
| 203 } | |
| 204 return path; | |
| 205 } | |
| 206 | |
| 207 void draw(Target* target, const GrGeometryProcessor* gp) const { | |
| 208 SkASSERT(!fAntiAlias); | |
| 209 GrResourceProvider* rp = target->resourceProvider(); | |
| 210 bool inverseFill = fShape.inverseFilled(); | |
| 157 // construct a cache key from the path's genID and the view matrix | 211 // construct a cache key from the path's genID and the view matrix |
| 158 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain() ; | 212 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain() ; |
| 159 GrUniqueKey key; | 213 GrUniqueKey key; |
| 160 static constexpr int kClipBoundsCnt = sizeof(fClipBounds) / sizeof(uint3 2_t); | 214 static constexpr int kClipBoundsCnt = sizeof(fDevClipBounds) / sizeof(ui nt32_t); |
| 161 int shapeKeyDataCnt = fShape.unstyledKeySize(); | 215 int shapeKeyDataCnt = fShape.unstyledKeySize(); |
| 162 SkASSERT(shapeKeyDataCnt >= 0); | 216 SkASSERT(shapeKeyDataCnt >= 0); |
| 163 GrUniqueKey::Builder builder(&key, kDomain, shapeKeyDataCnt + kClipBound sCnt); | 217 GrUniqueKey::Builder builder(&key, kDomain, shapeKeyDataCnt + kClipBound sCnt); |
| 164 fShape.writeUnstyledKey(&builder[0]); | 218 fShape.writeUnstyledKey(&builder[0]); |
| 165 // For inverse fills, the tessellation is dependent on clip bounds. | 219 // For inverse fills, the tessellation is dependent on clip bounds. |
| 166 if (inverseFill) { | 220 if (inverseFill) { |
| 167 memcpy(&builder[shapeKeyDataCnt], &fClipBounds, sizeof(fClipBounds)) ; | 221 memcpy(&builder[shapeKeyDataCnt], &fDevClipBounds, sizeof(fDevClipBo unds)); |
| 168 } else { | 222 } else { |
| 169 memset(&builder[shapeKeyDataCnt], 0, sizeof(fClipBounds)); | 223 memset(&builder[shapeKeyDataCnt], 0, sizeof(fDevClipBounds)); |
| 170 } | 224 } |
| 171 builder.finish(); | 225 builder.finish(); |
| 172 SkAutoTUnref<GrBuffer> cachedVertexBuffer(rp->findAndRefTByUniqueKey<GrB uffer>(key)); | 226 SkAutoTUnref<GrBuffer> cachedVertexBuffer(rp->findAndRefTByUniqueKey<GrB uffer>(key)); |
| 173 int actualCount; | 227 int actualCount; |
| 228 SkScalar tol = GrPathUtils::kDefaultTolerance; | |
| 229 tol = GrPathUtils::scaleToleranceToSrc(tol, fViewMatrix, fShape.bounds() ); | |
| 174 if (cache_match(cachedVertexBuffer.get(), tol, &actualCount)) { | 230 if (cache_match(cachedVertexBuffer.get(), tol, &actualCount)) { |
| 175 this->drawVertices(target, gp, cachedVertexBuffer.get(), 0, actualCo unt); | 231 this->drawVertices(target, gp, cachedVertexBuffer.get(), 0, actualCo unt); |
| 176 return; | 232 return; |
| 177 } | 233 } |
| 178 | 234 |
| 235 SkRect clipBounds = SkRect::Make(fDevClipBounds); | |
| 236 | |
| 237 SkMatrix vmi; | |
| 238 if (!fViewMatrix.invert(&vmi)) { | |
| 239 return; | |
| 240 } | |
| 241 vmi.mapRect(&clipBounds); | |
| 179 bool isLinear; | 242 bool isLinear; |
| 180 bool canMapVB = GrCaps::kNone_MapFlags != target->caps().mapBufferFlags( ); | 243 bool canMapVB = GrCaps::kNone_MapFlags != target->caps().mapBufferFlags( ); |
| 181 StaticVertexAllocator allocator(rp, canMapVB); | 244 StaticVertexAllocator allocator(gp->getVertexStride(), rp, canMapVB); |
| 182 int count = GrTessellator::PathToTriangles(path, tol, fClipBounds, &allo cator, &isLinear); | 245 int count = GrTessellator::PathToTriangles(getPath(), tol, clipBounds, & allocator, |
| 246 false, GrColor(), false, &isL inear); | |
| 183 if (count == 0) { | 247 if (count == 0) { |
| 184 return; | 248 return; |
| 185 } | 249 } |
| 186 this->drawVertices(target, gp, allocator.vertexBuffer(), 0, count); | 250 this->drawVertices(target, gp, allocator.vertexBuffer(), 0, count); |
| 187 TessInfo info; | 251 TessInfo info; |
| 188 info.fTolerance = isLinear ? 0 : tol; | 252 info.fTolerance = isLinear ? 0 : tol; |
| 189 info.fCount = count; | 253 info.fCount = count; |
| 190 key.setCustomData(SkData::MakeWithCopy(&info, sizeof(info))); | 254 key.setCustomData(SkData::MakeWithCopy(&info, sizeof(info))); |
| 191 rp->assignUniqueKeyToResource(key, allocator.vertexBuffer()); | 255 rp->assignUniqueKeyToResource(key, allocator.vertexBuffer()); |
| 192 } | 256 } |
| 193 | 257 |
| 258 void drawAA(Target* target, const GrGeometryProcessor* gp) const { | |
| 259 SkASSERT(fAntiAlias); | |
| 260 SkPath path = getPath(); | |
| 261 if (path.isEmpty()) { | |
| 262 return; | |
| 263 } | |
| 264 SkRect clipBounds = SkRect::Make(fDevClipBounds); | |
| 265 path.transform(fViewMatrix); | |
| 266 SkScalar tol = GrPathUtils::kDefaultTolerance; | |
| 267 bool isLinear; | |
| 268 DynamicVertexAllocator allocator(gp->getVertexStride(), target); | |
| 269 bool canTweakAlphaForCoverage = fPipelineInfo.canTweakAlphaForCoverage() ; | |
| 270 int count = GrTessellator::PathToTriangles(path, tol, clipBounds, &alloc ator, | |
| 271 true, fColor, canTweakAlphaFo rCoverage, | |
| 272 &isLinear); | |
| 273 if (count == 0) { | |
| 274 return; | |
| 275 } | |
| 276 drawVertices(target, gp, allocator.vertexBuffer(), allocator.firstVertex (), count); | |
| 277 } | |
| 278 | |
| 194 void onPrepareDraws(Target* target) const override { | 279 void onPrepareDraws(Target* target) const override { |
| 195 sk_sp<GrGeometryProcessor> gp; | 280 sk_sp<GrGeometryProcessor> gp; |
| 196 { | 281 { |
| 197 using namespace GrDefaultGeoProcFactory; | 282 using namespace GrDefaultGeoProcFactory; |
| 198 | 283 |
| 199 Color color(fColor); | 284 Color color(fColor); |
| 200 LocalCoords localCoords(fPipelineInfo.readsLocalCoords() ? | 285 LocalCoords localCoords(fPipelineInfo.readsLocalCoords() ? |
| 201 LocalCoords::kUsePosition_Type : | 286 LocalCoords::kUsePosition_Type : |
| 202 LocalCoords::kUnused_Type); | 287 LocalCoords::kUnused_Type); |
| 203 Coverage::Type coverageType; | 288 Coverage::Type coverageType; |
| 204 if (fPipelineInfo.readsCoverage()) { | 289 if (fAntiAlias) { |
| 290 color = Color(Color::kAttribute_Type); | |
| 291 if (fPipelineInfo.canTweakAlphaForCoverage()) { | |
| 292 coverageType = Coverage::kSolid_Type; | |
| 293 } else { | |
| 294 coverageType = Coverage::kAttribute_Type; | |
| 295 } | |
| 296 } else if (fPipelineInfo.readsCoverage()) { | |
| 205 coverageType = Coverage::kSolid_Type; | 297 coverageType = Coverage::kSolid_Type; |
| 206 } else { | 298 } else { |
| 207 coverageType = Coverage::kNone_Type; | 299 coverageType = Coverage::kNone_Type; |
| 208 } | 300 } |
| 209 Coverage coverage(coverageType); | 301 Coverage coverage(coverageType); |
| 210 gp = GrDefaultGeoProcFactory::Make(color, coverage, localCoords, fVi ewMatrix); | 302 if (fAntiAlias) { |
| 303 gp = GrDefaultGeoProcFactory::MakeForDeviceSpace(color, coverage , localCoords, | |
| 304 fViewMatrix); | |
| 305 } else { | |
| 306 gp = GrDefaultGeoProcFactory::Make(color, coverage, localCoords, fViewMatrix); | |
| 307 } | |
| 211 } | 308 } |
| 212 this->draw(target, gp.get()); | 309 if (fAntiAlias) { |
| 310 this->drawAA(target, gp.get()); | |
| 311 } else { | |
| 312 this->draw(target, gp.get()); | |
| 313 } | |
| 213 } | 314 } |
| 214 | 315 |
| 215 void drawVertices(Target* target, const GrGeometryProcessor* gp, const GrBuf fer* vb, | 316 void drawVertices(Target* target, const GrGeometryProcessor* gp, const GrBuf fer* vb, |
| 216 int firstVertex, int count) const { | 317 int firstVertex, int count) const { |
| 217 SkASSERT(gp->getVertexStride() == sizeof(SkPoint)); | |
| 218 | |
| 219 GrPrimitiveType primitiveType = TESSELLATOR_WIREFRAME ? kLines_GrPrimiti veType | 318 GrPrimitiveType primitiveType = TESSELLATOR_WIREFRAME ? kLines_GrPrimiti veType |
| 220 : kTriangles_GrPri mitiveType; | 319 : kTriangles_GrPri mitiveType; |
| 221 GrMesh mesh; | 320 GrMesh mesh; |
| 222 mesh.init(primitiveType, vb, firstVertex, count); | 321 mesh.init(primitiveType, vb, firstVertex, count); |
| 223 target->draw(gp, mesh); | 322 target->draw(gp, mesh); |
| 224 } | 323 } |
| 225 | 324 |
| 226 bool onCombineIfPossible(GrBatch*, const GrCaps&) override { return false; } | 325 bool onCombineIfPossible(GrBatch*, const GrCaps&) override { return false; } |
| 227 | 326 |
| 228 TessellatingPathBatch(const GrColor& color, | 327 TessellatingPathBatch(const GrColor& color, |
| 229 const GrShape& shape, | 328 const GrShape& shape, |
| 230 const SkMatrix& viewMatrix, | 329 const SkMatrix& viewMatrix, |
| 231 const SkRect& clipBounds) | 330 const SkIRect& devClipBounds, |
| 331 bool antiAlias) | |
| 232 : INHERITED(ClassID()) | 332 : INHERITED(ClassID()) |
| 233 , fColor(color) | 333 , fColor(color) |
| 234 , fShape(shape) | 334 , fShape(shape) |
| 235 , fViewMatrix(viewMatrix) { | 335 , fViewMatrix(viewMatrix) |
| 236 const SkRect& pathBounds = shape.bounds(); | 336 , fDevClipBounds(devClipBounds) |
| 237 fClipBounds = clipBounds; | 337 , fAntiAlias(antiAlias) { |
| 238 // Because the clip bounds are used to add a contour for inverse fills, they must also | 338 SkRect devBounds; |
| 239 // include the path bounds. | 339 viewMatrix.mapRect(&devBounds, shape.bounds()); |
| 240 fClipBounds.join(pathBounds); | 340 if (shape.inverseFilled()) { |
| 241 const SkRect& srcBounds = shape.inverseFilled() ? fClipBounds : pathBoun ds; | 341 // Because the clip bounds are used to add a contour for inverse fil ls, they must also |
| 242 this->setTransformedBounds(srcBounds, viewMatrix, HasAABloat::kNo, IsZer oArea::kNo); | 342 // include the path bounds. |
| 343 devBounds.join(SkRect::Make(fDevClipBounds)); | |
| 344 } | |
| 345 this->setBounds(devBounds, HasAABloat::kNo, IsZeroArea::kNo); | |
| 243 } | 346 } |
| 244 | 347 |
| 245 GrColor fColor; | 348 GrColor fColor; |
| 246 GrShape fShape; | 349 GrShape fShape; |
| 247 SkMatrix fViewMatrix; | 350 SkMatrix fViewMatrix; |
| 248 SkRect fClipBounds; // in source space | 351 SkIRect fDevClipBounds; |
| 352 bool fAntiAlias; | |
| 249 GrXPOverridesForBatch fPipelineInfo; | 353 GrXPOverridesForBatch fPipelineInfo; |
| 250 | 354 |
| 251 typedef GrVertexBatch INHERITED; | 355 typedef GrVertexBatch INHERITED; |
| 252 }; | 356 }; |
| 253 | 357 |
| 254 bool GrTessellatingPathRenderer::onDrawPath(const DrawPathArgs& args) { | 358 bool GrTessellatingPathRenderer::onDrawPath(const DrawPathArgs& args) { |
| 255 GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(), | 359 GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(), |
| 256 "GrTessellatingPathRenderer::onDrawPath"); | 360 "GrTessellatingPathRenderer::onDrawPath"); |
| 257 SkASSERT(!args.fAntiAlias); | |
| 258 | |
| 259 SkIRect clipBoundsI; | 361 SkIRect clipBoundsI; |
| 260 args.fClip->getConservativeBounds(args.fDrawContext->width(), args.fDrawCont ext->height(), | 362 args.fClip->getConservativeBounds(args.fDrawContext->width(), args.fDrawCont ext->height(), |
| 261 &clipBoundsI); | 363 &clipBoundsI); |
| 262 SkRect clipBounds = SkRect::Make(clipBoundsI); | |
| 263 SkMatrix vmi; | |
| 264 if (!args.fViewMatrix->invert(&vmi)) { | |
| 265 return false; | |
| 266 } | |
| 267 vmi.mapRect(&clipBounds); | |
| 268 SkPath path; | |
| 269 args.fShape->asPath(&path); | |
| 270 SkAutoTUnref<GrDrawBatch> batch(TessellatingPathBatch::Create(args.fPaint->g etColor(), | 364 SkAutoTUnref<GrDrawBatch> batch(TessellatingPathBatch::Create(args.fPaint->g etColor(), |
| 271 *args.fShape, | 365 *args.fShape, |
| 272 *args.fViewMat rix, clipBounds)); | 366 *args.fViewMat rix, |
| 367 clipBoundsI, | |
| 368 args.fAntiAlia s)); | |
| 273 | 369 |
| 274 GrPipelineBuilder pipelineBuilder(*args.fPaint, args.fDrawContext->mustUseHW AA(*args.fPaint)); | 370 GrPipelineBuilder pipelineBuilder(*args.fPaint, args.fDrawContext->mustUseHW AA(*args.fPaint)); |
| 275 pipelineBuilder.setUserStencil(args.fUserStencilSettings); | 371 pipelineBuilder.setUserStencil(args.fUserStencilSettings); |
| 276 | 372 |
| 277 args.fDrawContext->drawBatch(pipelineBuilder, *args.fClip, batch); | 373 args.fDrawContext->drawBatch(pipelineBuilder, *args.fClip, batch); |
| 278 | 374 |
| 279 return true; | 375 return true; |
| 280 } | 376 } |
| 281 | 377 |
| 282 //////////////////////////////////////////////////////////////////////////////// /////////////////// | 378 //////////////////////////////////////////////////////////////////////////////// /////////////////// |
| 283 | 379 |
| 284 #ifdef GR_TEST_UTILS | 380 #ifdef GR_TEST_UTILS |
| 285 | 381 |
| 286 DRAW_BATCH_TEST_DEFINE(TesselatingPathBatch) { | 382 DRAW_BATCH_TEST_DEFINE(TesselatingPathBatch) { |
| 287 GrColor color = GrRandomColor(random); | 383 GrColor color = GrRandomColor(random); |
| 288 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random); | 384 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random); |
| 289 SkPath path = GrTest::TestPath(random); | 385 SkPath path = GrTest::TestPath(random); |
| 290 SkRect clipBounds = GrTest::TestRect(random); | 386 SkIRect devClipBounds = SkIRect::MakeXYWH( |
| 291 SkMatrix vmi; | 387 random->nextU(), random->nextU(), random->nextU(), random->nextU()); |
| 292 bool result = viewMatrix.invert(&vmi); | 388 bool antiAlias = random->nextBool(); |
| 293 if (!result) { | |
| 294 SkFAIL("Cannot invert matrix\n"); | |
| 295 } | |
| 296 vmi.mapRect(&clipBounds); | |
| 297 GrStyle style; | 389 GrStyle style; |
| 298 do { | 390 do { |
| 299 GrTest::TestStyle(random, &style); | 391 GrTest::TestStyle(random, &style); |
| 300 } while (style.strokeRec().isHairlineStyle()); | 392 } while (style.strokeRec().isHairlineStyle()); |
| 301 GrShape shape(path, style); | 393 GrShape shape(path, style); |
| 302 return TessellatingPathBatch::Create(color, shape, viewMatrix, clipBounds); | 394 return TessellatingPathBatch::Create(color, shape, viewMatrix, devClipBounds , antiAlias); |
| 303 } | 395 } |
| 304 | 396 |
| 305 #endif | 397 #endif |
| OLD | NEW |