| 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 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 52 const SkData* data = vertexBuffer->getUniqueKey().getCustomData(); | 52 const SkData* data = vertexBuffer->getUniqueKey().getCustomData(); |
| 53 SkASSERT(data); | 53 SkASSERT(data); |
| 54 const TessInfo* info = static_cast<const TessInfo*>(data->data()); | 54 const TessInfo* info = static_cast<const TessInfo*>(data->data()); |
| 55 if (info->fTolerance == 0 || info->fTolerance < 3.0f * tol) { | 55 if (info->fTolerance == 0 || info->fTolerance < 3.0f * tol) { |
| 56 *actualCount = info->fCount; | 56 *actualCount = info->fCount; |
| 57 return true; | 57 return true; |
| 58 } | 58 } |
| 59 return false; | 59 return false; |
| 60 } | 60 } |
| 61 | 61 |
| 62 class StaticVertexAllocator : public GrTessellator::VertexAllocator { |
| 63 public: |
| 64 StaticVertexAllocator(SkAutoTUnref<GrVertexBuffer>& vertexBuffer, |
| 65 GrResourceProvider* resourceProvider, |
| 66 bool canMapVB) |
| 67 : fVertexBuffer(vertexBuffer) |
| 68 , fResourceProvider(resourceProvider) |
| 69 , fCanMapVB(canMapVB) |
| 70 , fVertices(nullptr) { |
| 71 } |
| 72 SkPoint* lock(int vertexCount) override { |
| 73 size_t size = vertexCount * sizeof(SkPoint); |
| 74 if (!fVertexBuffer.get() || fVertexBuffer->gpuMemorySize() < size) { |
| 75 fVertexBuffer.reset(fResourceProvider->createVertexBuffer( |
| 76 size, GrResourceProvider::kStatic_BufferUsage, 0)); |
| 77 } |
| 78 if (!fVertexBuffer.get()) { |
| 79 return nullptr; |
| 80 } |
| 81 if (fCanMapVB) { |
| 82 fVertices = static_cast<SkPoint*>(fVertexBuffer->map()); |
| 83 } else { |
| 84 fVertices = new SkPoint[vertexCount]; |
| 85 } |
| 86 return fVertices; |
| 87 } |
| 88 void unlock(int actualCount) override { |
| 89 if (fCanMapVB) { |
| 90 fVertexBuffer->unmap(); |
| 91 } else { |
| 92 fVertexBuffer->updateData(fVertices, actualCount * sizeof(SkPoint)); |
| 93 delete[] fVertices; |
| 94 } |
| 95 fVertices = nullptr; |
| 96 } |
| 97 private: |
| 98 SkAutoTUnref<GrVertexBuffer>& fVertexBuffer; |
| 99 GrResourceProvider* fResourceProvider; |
| 100 bool fCanMapVB; |
| 101 SkPoint* fVertices; |
| 102 }; |
| 103 |
| 62 } // namespace | 104 } // namespace |
| 63 | 105 |
| 64 GrTessellatingPathRenderer::GrTessellatingPathRenderer() { | 106 GrTessellatingPathRenderer::GrTessellatingPathRenderer() { |
| 65 } | 107 } |
| 66 | 108 |
| 67 bool GrTessellatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) cons
t { | 109 bool GrTessellatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) cons
t { |
| 68 // This path renderer can draw all fill styles, all stroke styles except hai
rlines, but does | 110 // This path renderer can draw all fill styles, all stroke styles except hai
rlines, but does |
| 69 // not do antialiasing. It can do convex and concave paths, but we'll leave
the convex ones to | 111 // not do antialiasing. It can do convex and concave paths, but we'll leave
the convex ones to |
| 70 // simpler algorithms. | 112 // simpler algorithms. |
| 71 return !IsStrokeHairlineOrEquivalent(*args.fStroke, *args.fViewMatrix, nullp
tr) && | 113 return !IsStrokeHairlineOrEquivalent(*args.fStroke, *args.fViewMatrix, nullp
tr) && |
| (...skipping 24 matching lines...) Expand all Loading... |
| 96 private: | 138 private: |
| 97 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { | 139 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { |
| 98 // Handle any color overrides | 140 // Handle any color overrides |
| 99 if (!overrides.readsColor()) { | 141 if (!overrides.readsColor()) { |
| 100 fColor = GrColor_ILLEGAL; | 142 fColor = GrColor_ILLEGAL; |
| 101 } | 143 } |
| 102 overrides.getOverrideColorIfSet(&fColor); | 144 overrides.getOverrideColorIfSet(&fColor); |
| 103 fPipelineInfo = overrides; | 145 fPipelineInfo = overrides; |
| 104 } | 146 } |
| 105 | 147 |
| 106 int tessellate(GrUniqueKey* key, | 148 void draw(Target* target, const GrGeometryProcessor* gp) const { |
| 107 GrResourceProvider* resourceProvider, | |
| 108 SkAutoTUnref<GrVertexBuffer>& vertexBuffer, | |
| 109 bool canMapVB) const { | |
| 110 SkPath path; | |
| 111 GrStrokeInfo stroke(fStroke); | |
| 112 if (stroke.isDashed()) { | |
| 113 if (!stroke.applyDashToPath(&path, &stroke, fPath)) { | |
| 114 return 0; | |
| 115 } | |
| 116 } else { | |
| 117 path = fPath; | |
| 118 } | |
| 119 if (!stroke.isFillStyle()) { | |
| 120 stroke.setResScale(SkScalarAbs(fViewMatrix.getMaxScale())); | |
| 121 if (!stroke.applyToPath(&path, path)) { | |
| 122 return 0; | |
| 123 } | |
| 124 stroke.setFillStyle(); | |
| 125 } | |
| 126 SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance; | |
| 127 SkRect pathBounds = path.getBounds(); | |
| 128 SkScalar tol = GrPathUtils::scaleToleranceToSrc(screenSpaceTol, fViewMat
rix, pathBounds); | |
| 129 | |
| 130 bool isLinear; | |
| 131 int count = GrTessellator::PathToTriangles(path, tol, fClipBounds, resou
rceProvider, | |
| 132 vertexBuffer, canMapVB, &isLi
near); | |
| 133 if (!fPath.isVolatile()) { | |
| 134 TessInfo info; | |
| 135 info.fTolerance = isLinear ? 0 : tol; | |
| 136 info.fCount = count; | |
| 137 SkAutoTUnref<SkData> data(SkData::NewWithCopy(&info, sizeof(info))); | |
| 138 key->setCustomData(data.get()); | |
| 139 resourceProvider->assignUniqueKeyToResource(*key, vertexBuffer.get()
); | |
| 140 SkPathPriv::AddGenIDChangeListener(fPath, new PathInvalidator(*key))
; | |
| 141 } | |
| 142 return count; | |
| 143 } | |
| 144 | |
| 145 void onPrepareDraws(Target* target) const override { | |
| 146 // construct a cache key from the path's genID and the view matrix | 149 // construct a cache key from the path's genID and the view matrix |
| 147 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain()
; | 150 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain()
; |
| 148 GrUniqueKey key; | 151 GrUniqueKey key; |
| 149 int clipBoundsSize32 = | 152 int clipBoundsSize32 = |
| 150 fPath.isInverseFillType() ? sizeof(fClipBounds) / sizeof(uint32_t) :
0; | 153 fPath.isInverseFillType() ? sizeof(fClipBounds) / sizeof(uint32_t) :
0; |
| 151 int strokeDataSize32 = fStroke.computeUniqueKeyFragmentData32Cnt(); | 154 int strokeDataSize32 = fStroke.computeUniqueKeyFragmentData32Cnt(); |
| 152 GrUniqueKey::Builder builder(&key, kDomain, 2 + clipBoundsSize32 + strok
eDataSize32); | 155 GrUniqueKey::Builder builder(&key, kDomain, 2 + clipBoundsSize32 + strok
eDataSize32); |
| 153 builder[0] = fPath.getGenerationID(); | 156 builder[0] = fPath.getGenerationID(); |
| 154 builder[1] = fPath.getFillType(); | 157 builder[1] = fPath.getFillType(); |
| 155 // For inverse fills, the tessellation is dependent on clip bounds. | 158 // For inverse fills, the tessellation is dependent on clip bounds. |
| 156 if (fPath.isInverseFillType()) { | 159 if (fPath.isInverseFillType()) { |
| 157 memcpy(&builder[2], &fClipBounds, sizeof(fClipBounds)); | 160 memcpy(&builder[2], &fClipBounds, sizeof(fClipBounds)); |
| 158 } | 161 } |
| 159 fStroke.asUniqueKeyFragment(&builder[2 + clipBoundsSize32]); | 162 fStroke.asUniqueKeyFragment(&builder[2 + clipBoundsSize32]); |
| 160 builder.finish(); | 163 builder.finish(); |
| 161 GrResourceProvider* rp = target->resourceProvider(); | 164 GrResourceProvider* rp = target->resourceProvider(); |
| 162 SkAutoTUnref<GrVertexBuffer> vertexBuffer(rp->findAndRefTByUniqueKey<GrV
ertexBuffer>(key)); | 165 SkAutoTUnref<GrVertexBuffer> vertexBuffer(rp->findAndRefTByUniqueKey<GrV
ertexBuffer>(key)); |
| 163 int actualCount; | 166 int actualCount; |
| 164 SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance; | 167 SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance; |
| 165 SkScalar tol = GrPathUtils::scaleToleranceToSrc( | 168 SkScalar tol = GrPathUtils::scaleToleranceToSrc( |
| 166 screenSpaceTol, fViewMatrix, fPath.getBounds()); | 169 screenSpaceTol, fViewMatrix, fPath.getBounds()); |
| 167 if (!cache_match(vertexBuffer.get(), tol, &actualCount)) { | 170 if (cache_match(vertexBuffer.get(), tol, &actualCount)) { |
| 168 bool canMapVB = GrCaps::kNone_MapFlags != target->caps().mapBufferFl
ags(); | 171 this->drawVertices(target, gp, vertexBuffer.get(), 0, actualCount); |
| 169 actualCount = this->tessellate(&key, rp, vertexBuffer, canMapVB); | |
| 170 } | |
| 171 | |
| 172 if (actualCount == 0) { | |
| 173 return; | 172 return; |
| 174 } | 173 } |
| 175 | 174 |
| 175 SkPath path; |
| 176 GrStrokeInfo stroke(fStroke); |
| 177 if (stroke.isDashed()) { |
| 178 if (!stroke.applyDashToPath(&path, &stroke, fPath)) { |
| 179 return; |
| 180 } |
| 181 } else { |
| 182 path = fPath; |
| 183 } |
| 184 if (!stroke.isFillStyle()) { |
| 185 stroke.setResScale(SkScalarAbs(fViewMatrix.getMaxScale())); |
| 186 if (!stroke.applyToPath(&path, path)) { |
| 187 return; |
| 188 } |
| 189 stroke.setFillStyle(); |
| 190 } |
| 191 bool isLinear; |
| 192 bool canMapVB = GrCaps::kNone_MapFlags != target->caps().mapBufferFlags(
); |
| 193 StaticVertexAllocator allocator(vertexBuffer, target->resourceProvider()
, canMapVB); |
| 194 int count = GrTessellator::PathToTriangles(path, tol, fClipBounds, &allo
cator, &isLinear); |
| 195 if (count == 0) { |
| 196 return; |
| 197 } |
| 198 this->drawVertices(target, gp, vertexBuffer.get(), 0, count); |
| 199 if (!fPath.isVolatile()) { |
| 200 TessInfo info; |
| 201 info.fTolerance = isLinear ? 0 : tol; |
| 202 info.fCount = count; |
| 203 SkAutoTUnref<SkData> data(SkData::NewWithCopy(&info, sizeof(info))); |
| 204 key.setCustomData(data.get()); |
| 205 target->resourceProvider()->assignUniqueKeyToResource(key, vertexBuf
fer.get()); |
| 206 SkPathPriv::AddGenIDChangeListener(fPath, new PathInvalidator(key)); |
| 207 } |
| 208 } |
| 209 |
| 210 void onPrepareDraws(Target* target) const override { |
| 176 SkAutoTUnref<const GrGeometryProcessor> gp; | 211 SkAutoTUnref<const GrGeometryProcessor> gp; |
| 177 { | 212 { |
| 178 using namespace GrDefaultGeoProcFactory; | 213 using namespace GrDefaultGeoProcFactory; |
| 179 | 214 |
| 180 Color color(fColor); | 215 Color color(fColor); |
| 181 LocalCoords localCoords(fPipelineInfo.readsLocalCoords() ? | 216 LocalCoords localCoords(fPipelineInfo.readsLocalCoords() ? |
| 182 LocalCoords::kUsePosition_Type : | 217 LocalCoords::kUsePosition_Type : |
| 183 LocalCoords::kUnused_Type); | 218 LocalCoords::kUnused_Type); |
| 184 Coverage::Type coverageType; | 219 Coverage::Type coverageType; |
| 185 if (fPipelineInfo.readsCoverage()) { | 220 if (fPipelineInfo.readsCoverage()) { |
| 186 coverageType = Coverage::kSolid_Type; | 221 coverageType = Coverage::kSolid_Type; |
| 187 } else { | 222 } else { |
| 188 coverageType = Coverage::kNone_Type; | 223 coverageType = Coverage::kNone_Type; |
| 189 } | 224 } |
| 190 Coverage coverage(coverageType); | 225 Coverage coverage(coverageType); |
| 191 gp.reset(GrDefaultGeoProcFactory::Create(color, coverage, localCoord
s, | 226 gp.reset(GrDefaultGeoProcFactory::Create(color, coverage, localCoord
s, |
| 192 fViewMatrix)); | 227 fViewMatrix)); |
| 193 } | 228 } |
| 229 this->draw(target, gp.get()); |
| 230 } |
| 194 | 231 |
| 232 void drawVertices(Target* target, const GrGeometryProcessor* gp, const GrVer
texBuffer* vb, |
| 233 int firstVertex, int count) const { |
| 195 target->initDraw(gp, this->pipeline()); | 234 target->initDraw(gp, this->pipeline()); |
| 196 SkASSERT(gp->getVertexStride() == sizeof(SkPoint)); | 235 SkASSERT(gp->getVertexStride() == sizeof(SkPoint)); |
| 197 | 236 |
| 198 GrPrimitiveType primitiveType = TESSELLATOR_WIREFRAME ? kLines_GrPrimiti
veType | 237 GrPrimitiveType primitiveType = TESSELLATOR_WIREFRAME ? kLines_GrPrimiti
veType |
| 199 : kTriangles_GrPri
mitiveType; | 238 : kTriangles_GrPri
mitiveType; |
| 200 GrVertices vertices; | 239 GrVertices vertices; |
| 201 vertices.init(primitiveType, vertexBuffer.get(), 0, actualCount); | 240 vertices.init(primitiveType, vb, firstVertex, count); |
| 202 target->draw(vertices); | 241 target->draw(vertices); |
| 203 } | 242 } |
| 204 | 243 |
| 205 bool onCombineIfPossible(GrBatch*, const GrCaps&) override { return false; } | 244 bool onCombineIfPossible(GrBatch*, const GrCaps&) override { return false; } |
| 206 | 245 |
| 207 TessellatingPathBatch(const GrColor& color, | 246 TessellatingPathBatch(const GrColor& color, |
| 208 const SkPath& path, | 247 const SkPath& path, |
| 209 const GrStrokeInfo& stroke, | 248 const GrStrokeInfo& stroke, |
| 210 const SkMatrix& viewMatrix, | 249 const SkMatrix& viewMatrix, |
| 211 const SkRect& clipBounds) | 250 const SkRect& clipBounds) |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 285 bool result = viewMatrix.invert(&vmi); | 324 bool result = viewMatrix.invert(&vmi); |
| 286 if (!result) { | 325 if (!result) { |
| 287 SkFAIL("Cannot invert matrix\n"); | 326 SkFAIL("Cannot invert matrix\n"); |
| 288 } | 327 } |
| 289 vmi.mapRect(&clipBounds); | 328 vmi.mapRect(&clipBounds); |
| 290 GrStrokeInfo strokeInfo = GrTest::TestStrokeInfo(random); | 329 GrStrokeInfo strokeInfo = GrTest::TestStrokeInfo(random); |
| 291 return TessellatingPathBatch::Create(color, path, strokeInfo, viewMatrix, cl
ipBounds); | 330 return TessellatingPathBatch::Create(color, path, strokeInfo, viewMatrix, cl
ipBounds); |
| 292 } | 331 } |
| 293 | 332 |
| 294 #endif | 333 #endif |
| OLD | NEW |