| OLD | NEW |
| (Empty) |
| 1 | |
| 2 /* | |
| 3 * Copyright 2015 Google Inc. | |
| 4 * | |
| 5 * Use of this source code is governed by a BSD-style license that can be | |
| 6 * found in the LICENSE file. | |
| 7 */ | |
| 8 | |
| 9 #include "GrAALinearizingConvexPathRenderer.h" | |
| 10 | |
| 11 #include "GrAAConvexTessellator.h" | |
| 12 #include "GrBatchFlushState.h" | |
| 13 #include "GrBatchTest.h" | |
| 14 #include "GrContext.h" | |
| 15 #include "GrDefaultGeoProcFactory.h" | |
| 16 #include "GrGeometryProcessor.h" | |
| 17 #include "GrInvariantOutput.h" | |
| 18 #include "GrPathUtils.h" | |
| 19 #include "GrProcessor.h" | |
| 20 #include "GrPipelineBuilder.h" | |
| 21 #include "GrStrokeInfo.h" | |
| 22 #include "SkGeometry.h" | |
| 23 #include "SkString.h" | |
| 24 #include "SkTraceEvent.h" | |
| 25 #include "SkPathPriv.h" | |
| 26 #include "batches/GrVertexBatch.h" | |
| 27 #include "gl/GrGLProcessor.h" | |
| 28 #include "gl/GrGLGeometryProcessor.h" | |
| 29 #include "gl/builders/GrGLProgramBuilder.h" | |
| 30 | |
| 31 static const int DEFAULT_BUFFER_SIZE = 100; | |
| 32 | |
| 33 // The thicker the stroke, the harder it is to produce high-quality results usin
g tessellation. For | |
| 34 // the time being, we simply drop back to software rendering above this stroke w
idth. | |
| 35 static const SkScalar kMaxStrokeWidth = 20.0; | |
| 36 | |
| 37 GrAALinearizingConvexPathRenderer::GrAALinearizingConvexPathRenderer() { | |
| 38 } | |
| 39 | |
| 40 /////////////////////////////////////////////////////////////////////////////// | |
| 41 | |
| 42 bool GrAALinearizingConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& arg
s) const { | |
| 43 if (!args.fAntiAlias) { | |
| 44 return false; | |
| 45 } | |
| 46 if (args.fPath->isInverseFillType()) { | |
| 47 return false; | |
| 48 } | |
| 49 if (!args.fPath->isConvex()) { | |
| 50 return false; | |
| 51 } | |
| 52 if (args.fStroke->getStyle() == SkStrokeRec::kStroke_Style) { | |
| 53 if (!args.fViewMatrix->isSimilarity()) { | |
| 54 return false; | |
| 55 } | |
| 56 SkScalar strokeWidth = args.fViewMatrix->getMaxScale() * args.fStroke->g
etWidth(); | |
| 57 return strokeWidth >= 1.0f && strokeWidth <= kMaxStrokeWidth && !args.fS
troke->isDashed() && | |
| 58 SkPathPriv::LastVerbIsClose(*args.fPath) && | |
| 59 args.fStroke->getJoin() != SkPaint::Join::kRound_Join; | |
| 60 } | |
| 61 return args.fStroke->getStyle() == SkStrokeRec::kFill_Style; | |
| 62 } | |
| 63 | |
| 64 // extract the result vertices and indices from the GrAAConvexTessellator | |
| 65 static void extract_verts(const GrAAConvexTessellator& tess, | |
| 66 void* vertices, | |
| 67 size_t vertexStride, | |
| 68 GrColor color, | |
| 69 uint16_t firstIndex, | |
| 70 uint16_t* idxs, | |
| 71 bool tweakAlphaForCoverage) { | |
| 72 intptr_t verts = reinterpret_cast<intptr_t>(vertices); | |
| 73 | |
| 74 for (int i = 0; i < tess.numPts(); ++i) { | |
| 75 *((SkPoint*)((intptr_t)verts + i * vertexStride)) = tess.point(i); | |
| 76 } | |
| 77 | |
| 78 // Make 'verts' point to the colors | |
| 79 verts += sizeof(SkPoint); | |
| 80 for (int i = 0; i < tess.numPts(); ++i) { | |
| 81 if (tweakAlphaForCoverage) { | |
| 82 SkASSERT(SkScalarRoundToInt(255.0f * tess.coverage(i)) <= 255); | |
| 83 unsigned scale = SkScalarRoundToInt(255.0f * tess.coverage(i)); | |
| 84 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, s
cale); | |
| 85 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor; | |
| 86 } else { | |
| 87 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color; | |
| 88 *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)
) = | |
| 89 tess.coverage(i); | |
| 90 } | |
| 91 } | |
| 92 | |
| 93 for (int i = 0; i < tess.numIndices(); ++i) { | |
| 94 idxs[i] = tess.index(i) + firstIndex; | |
| 95 } | |
| 96 } | |
| 97 | |
| 98 static const GrGeometryProcessor* create_fill_gp(bool tweakAlphaForCoverage, | |
| 99 const SkMatrix& viewMatrix, | |
| 100 bool usesLocalCoords, | |
| 101 bool coverageIgnored) { | |
| 102 using namespace GrDefaultGeoProcFactory; | |
| 103 | |
| 104 Color color(Color::kAttribute_Type); | |
| 105 Coverage::Type coverageType; | |
| 106 // TODO remove coverage if coverage is ignored | |
| 107 /*if (coverageIgnored) { | |
| 108 coverageType = Coverage::kNone_Type; | |
| 109 } else*/ if (tweakAlphaForCoverage) { | |
| 110 coverageType = Coverage::kSolid_Type; | |
| 111 } else { | |
| 112 coverageType = Coverage::kAttribute_Type; | |
| 113 } | |
| 114 Coverage coverage(coverageType); | |
| 115 LocalCoords localCoords(usesLocalCoords ? LocalCoords::kUsePosition_Type : | |
| 116 LocalCoords::kUnused_Type); | |
| 117 return CreateForDeviceSpace(color, coverage, localCoords, viewMatrix); | |
| 118 } | |
| 119 | |
| 120 class AAFlatteningConvexPathBatch : public GrVertexBatch { | |
| 121 public: | |
| 122 struct Geometry { | |
| 123 GrColor fColor; | |
| 124 SkMatrix fViewMatrix; | |
| 125 SkPath fPath; | |
| 126 SkScalar fStrokeWidth; | |
| 127 SkPaint::Join fJoin; | |
| 128 SkScalar fMiterLimit; | |
| 129 }; | |
| 130 | |
| 131 static GrDrawBatch* Create(const Geometry& geometry) { | |
| 132 return new AAFlatteningConvexPathBatch(geometry); | |
| 133 } | |
| 134 | |
| 135 const char* name() const override { return "AAConvexBatch"; } | |
| 136 | |
| 137 void getInvariantOutputColor(GrInitInvariantOutput* out) const override { | |
| 138 // When this is called on a batch, there is only one geometry bundle | |
| 139 out->setKnownFourComponents(fGeoData[0].fColor); | |
| 140 } | |
| 141 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override { | |
| 142 out->setUnknownSingleComponent(); | |
| 143 } | |
| 144 | |
| 145 private: | |
| 146 void initBatchTracker(const GrPipelineOptimizations& opt) override { | |
| 147 // Handle any color overrides | |
| 148 if (!opt.readsColor()) { | |
| 149 fGeoData[0].fColor = GrColor_ILLEGAL; | |
| 150 } | |
| 151 opt.getOverrideColorIfSet(&fGeoData[0].fColor); | |
| 152 | |
| 153 // setup batch properties | |
| 154 fBatch.fColorIgnored = !opt.readsColor(); | |
| 155 fBatch.fColor = fGeoData[0].fColor; | |
| 156 fBatch.fUsesLocalCoords = opt.readsLocalCoords(); | |
| 157 fBatch.fCoverageIgnored = !opt.readsCoverage(); | |
| 158 fBatch.fLinesOnly = SkPath::kLine_SegmentMask == fGeoData[0].fPath.getSe
gmentMasks(); | |
| 159 fBatch.fCanTweakAlphaForCoverage = opt.canTweakAlphaForCoverage(); | |
| 160 } | |
| 161 | |
| 162 void draw(GrVertexBatch::Target* target, const GrPipeline* pipeline, int ver
texCount, | |
| 163 size_t vertexStride, void* vertices, int indexCount, uint16_t* indic
es) { | |
| 164 if (vertexCount == 0 || indexCount == 0) { | |
| 165 return; | |
| 166 } | |
| 167 const GrVertexBuffer* vertexBuffer; | |
| 168 GrVertices info; | |
| 169 int firstVertex; | |
| 170 void* verts = target->makeVertexSpace(vertexStride, vertexCount, &vertex
Buffer, | |
| 171 &firstVertex); | |
| 172 if (!verts) { | |
| 173 SkDebugf("Could not allocate vertices\n"); | |
| 174 return; | |
| 175 } | |
| 176 memcpy(verts, vertices, vertexCount * vertexStride); | |
| 177 | |
| 178 const GrIndexBuffer* indexBuffer; | |
| 179 int firstIndex; | |
| 180 uint16_t* idxs = target->makeIndexSpace(indexCount, &indexBuffer, &first
Index); | |
| 181 if (!idxs) { | |
| 182 SkDebugf("Could not allocate indices\n"); | |
| 183 return; | |
| 184 } | |
| 185 memcpy(idxs, indices, indexCount * sizeof(uint16_t)); | |
| 186 info.initIndexed(kTriangles_GrPrimitiveType, vertexBuffer, indexBuffer,
firstVertex, | |
| 187 firstIndex, vertexCount, indexCount); | |
| 188 target->draw(info); | |
| 189 } | |
| 190 | |
| 191 void onPrepareDraws(Target* target) override { | |
| 192 bool canTweakAlphaForCoverage = this->canTweakAlphaForCoverage(); | |
| 193 | |
| 194 // Setup GrGeometryProcessor | |
| 195 SkAutoTUnref<const GrGeometryProcessor> gp(create_fill_gp(canTweakAlphaF
orCoverage, | |
| 196 this->viewMatr
ix(), | |
| 197 this->usesLoca
lCoords(), | |
| 198 this->coverage
Ignored())); | |
| 199 if (!gp) { | |
| 200 SkDebugf("Couldn't create a GrGeometryProcessor\n"); | |
| 201 return; | |
| 202 } | |
| 203 | |
| 204 target->initDraw(gp, this->pipeline()); | |
| 205 | |
| 206 size_t vertexStride = gp->getVertexStride(); | |
| 207 | |
| 208 SkASSERT(canTweakAlphaForCoverage ? | |
| 209 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAt
tr) : | |
| 210 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorCo
verageAttr)); | |
| 211 | |
| 212 int instanceCount = fGeoData.count(); | |
| 213 | |
| 214 int vertexCount = 0; | |
| 215 int indexCount = 0; | |
| 216 int maxVertices = DEFAULT_BUFFER_SIZE; | |
| 217 int maxIndices = DEFAULT_BUFFER_SIZE; | |
| 218 uint8_t* vertices = (uint8_t*) sk_malloc_throw(maxVertices * vertexStrid
e); | |
| 219 uint16_t* indices = (uint16_t*) sk_malloc_throw(maxIndices * sizeof(uint
16_t)); | |
| 220 for (int i = 0; i < instanceCount; i++) { | |
| 221 Geometry& args = fGeoData[i]; | |
| 222 GrAAConvexTessellator tess(args.fStrokeWidth, args.fJoin, args.fMite
rLimit); | |
| 223 | |
| 224 if (!tess.tessellate(args.fViewMatrix, args.fPath)) { | |
| 225 continue; | |
| 226 } | |
| 227 | |
| 228 int currentIndices = tess.numIndices(); | |
| 229 SkASSERT(currentIndices <= UINT16_MAX); | |
| 230 if (indexCount + currentIndices > UINT16_MAX) { | |
| 231 // if we added the current instance, we would overflow the indic
es we can store in a | |
| 232 // uint16_t. Draw what we've got so far and reset. | |
| 233 draw(target, this->pipeline(), vertexCount, vertexStride, vertic
es, indexCount, | |
| 234 indices); | |
| 235 vertexCount = 0; | |
| 236 indexCount = 0; | |
| 237 } | |
| 238 int currentVertices = tess.numPts(); | |
| 239 if (vertexCount + currentVertices > maxVertices) { | |
| 240 maxVertices = SkTMax(vertexCount + currentVertices, maxVertices
* 2); | |
| 241 vertices = (uint8_t*) sk_realloc_throw(vertices, maxVertices * v
ertexStride); | |
| 242 } | |
| 243 if (indexCount + currentIndices > maxIndices) { | |
| 244 maxIndices = SkTMax(indexCount + currentIndices, maxIndices * 2)
; | |
| 245 indices = (uint16_t*) sk_realloc_throw(indices, maxIndices * siz
eof(uint16_t)); | |
| 246 } | |
| 247 | |
| 248 extract_verts(tess, vertices + vertexStride * vertexCount, vertexStr
ide, args.fColor, | |
| 249 vertexCount, indices + indexCount, canTweakAlphaForCoverage)
; | |
| 250 vertexCount += currentVertices; | |
| 251 indexCount += currentIndices; | |
| 252 } | |
| 253 draw(target, this->pipeline(), vertexCount, vertexStride, vertices, inde
xCount, | |
| 254 indices); | |
| 255 sk_free(vertices); | |
| 256 sk_free(indices); | |
| 257 } | |
| 258 | |
| 259 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; } | |
| 260 | |
| 261 AAFlatteningConvexPathBatch(const Geometry& geometry) { | |
| 262 this->initClassID<AAFlatteningConvexPathBatch>(); | |
| 263 fGeoData.push_back(geometry); | |
| 264 | |
| 265 // compute bounds | |
| 266 fBounds = geometry.fPath.getBounds(); | |
| 267 geometry.fViewMatrix.mapRect(&fBounds); | |
| 268 } | |
| 269 | |
| 270 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { | |
| 271 AAFlatteningConvexPathBatch* that = t->cast<AAFlatteningConvexPathBatch>
(); | |
| 272 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pi
peline(), | |
| 273 that->bounds(), caps)) { | |
| 274 return false; | |
| 275 } | |
| 276 | |
| 277 SkASSERT(this->usesLocalCoords() == that->usesLocalCoords()); | |
| 278 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->vi
ewMatrix())) { | |
| 279 return false; | |
| 280 } | |
| 281 | |
| 282 // In the event of two batches, one who can tweak, one who cannot, we ju
st fall back to | |
| 283 // not tweaking | |
| 284 if (this->canTweakAlphaForCoverage() != that->canTweakAlphaForCoverage()
) { | |
| 285 fBatch.fCanTweakAlphaForCoverage = false; | |
| 286 } | |
| 287 | |
| 288 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin())
; | |
| 289 this->joinBounds(that->bounds()); | |
| 290 return true; | |
| 291 } | |
| 292 | |
| 293 GrColor color() const { return fBatch.fColor; } | |
| 294 bool linesOnly() const { return fBatch.fLinesOnly; } | |
| 295 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } | |
| 296 bool canTweakAlphaForCoverage() const { return fBatch.fCanTweakAlphaForCover
age; } | |
| 297 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; } | |
| 298 bool coverageIgnored() const { return fBatch.fCoverageIgnored; } | |
| 299 | |
| 300 struct BatchTracker { | |
| 301 GrColor fColor; | |
| 302 bool fUsesLocalCoords; | |
| 303 bool fColorIgnored; | |
| 304 bool fCoverageIgnored; | |
| 305 bool fLinesOnly; | |
| 306 bool fCanTweakAlphaForCoverage; | |
| 307 }; | |
| 308 | |
| 309 BatchTracker fBatch; | |
| 310 SkSTArray<1, Geometry, true> fGeoData; | |
| 311 }; | |
| 312 | |
| 313 bool GrAALinearizingConvexPathRenderer::onDrawPath(const DrawPathArgs& args) { | |
| 314 if (args.fPath->isEmpty()) { | |
| 315 return true; | |
| 316 } | |
| 317 AAFlatteningConvexPathBatch::Geometry geometry; | |
| 318 geometry.fColor = args.fColor; | |
| 319 geometry.fViewMatrix = *args.fViewMatrix; | |
| 320 geometry.fPath = *args.fPath; | |
| 321 geometry.fStrokeWidth = args.fStroke->isFillStyle() ? -1.0f : args.fStroke->
getWidth(); | |
| 322 geometry.fJoin = args.fStroke->isFillStyle() ? SkPaint::Join::kMiter_Join : | |
| 323 args.fStroke->getJoin(); | |
| 324 geometry.fMiterLimit = args.fStroke->getMiter(); | |
| 325 | |
| 326 SkAutoTUnref<GrDrawBatch> batch(AAFlatteningConvexPathBatch::Create(geometry
)); | |
| 327 args.fTarget->drawBatch(*args.fPipelineBuilder, batch); | |
| 328 | |
| 329 return true; | |
| 330 } | |
| 331 | |
| 332 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | |
| 333 | |
| 334 #ifdef GR_TEST_UTILS | |
| 335 | |
| 336 DRAW_BATCH_TEST_DEFINE(AAFlatteningConvexPathBatch) { | |
| 337 AAFlatteningConvexPathBatch::Geometry geometry; | |
| 338 geometry.fColor = GrRandomColor(random); | |
| 339 geometry.fViewMatrix = GrTest::TestMatrixInvertible(random); | |
| 340 geometry.fPath = GrTest::TestPathConvex(random); | |
| 341 | |
| 342 return AAFlatteningConvexPathBatch::Create(geometry); | |
| 343 } | |
| 344 | |
| 345 #endif | |
| OLD | NEW |