Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 | |
| 2 /* | |
|
robertphillips
2015/05/27 18:10:53
Update this ?
ethannicholas
2015/05/27 19:22:30
Done.
| |
| 3 * Copyright 2012 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 "GrAAFlatteningConvexPathRenderer.h" | |
| 10 | |
| 11 #include "GrAAFlatteningConvexTessellator.h" | |
| 12 #include "GrBatch.h" | |
| 13 #include "GrBatchTarget.h" | |
| 14 #include "GrBatchTest.h" | |
| 15 #include "GrContext.h" | |
| 16 #include "GrDefaultGeoProcFactory.h" | |
| 17 #include "GrGeometryProcessor.h" | |
| 18 #include "GrInvariantOutput.h" | |
| 19 #include "GrPathUtils.h" | |
| 20 #include "GrProcessor.h" | |
| 21 #include "GrPipelineBuilder.h" | |
| 22 #include "GrStrokeInfo.h" | |
| 23 #include "SkGeometry.h" | |
| 24 #include "SkString.h" | |
| 25 #include "SkTraceEvent.h" | |
| 26 #include "gl/GrGLProcessor.h" | |
| 27 #include "gl/GrGLSL.h" | |
| 28 #include "gl/GrGLGeometryProcessor.h" | |
| 29 #include "gl/builders/GrGLProgramBuilder.h" | |
| 30 | |
| 31 #define DEFAULT_BUFFER_SIZE 100 | |
| 32 | |
| 33 GrAAFlatteningConvexPathRenderer::GrAAFlatteningConvexPathRenderer() { | |
| 34 } | |
| 35 | |
| 36 /////////////////////////////////////////////////////////////////////////////// | |
| 37 | |
| 38 bool GrAAFlatteningConvexPathRenderer::canDrawPath(const GrDrawTarget* target, | |
|
robertphillips
2015/05/27 18:10:54
Align these guys ?
ethannicholas
2015/05/27 19:22:30
Done.
| |
| 39 const GrPipelineBuilder*, | |
| 40 const SkMatrix& viewMatrix, | |
| 41 const SkPath& path, | |
| 42 const GrStrokeInfo& stroke, | |
| 43 bool antiAlias) const { | |
| 44 return (target->caps()->shaderCaps()->shaderDerivativeSupport() && antiAlias && | |
|
bsalomon
2015/05/27 17:11:07
probably don't need shader derivative support anym
ethannicholas
2015/05/27 19:22:30
Done.
| |
| 45 stroke.isFillStyle() && !path.isInverseFillType() && path.isConvex() ); | |
| 46 } | |
| 47 | |
| 48 // extract the result vertices and indices from the GrAAFlatteningConvexTessella tor | |
| 49 static void extract_verts(const GrAAFlatteningConvexTessellator& tess, | |
| 50 void* vertices, | |
| 51 size_t vertexStride, | |
| 52 GrColor color, | |
| 53 uint16_t firstIndex, | |
| 54 uint16_t* idxs, | |
| 55 bool tweakAlphaForCoverage) { | |
| 56 intptr_t verts = reinterpret_cast<intptr_t>(vertices); | |
| 57 | |
| 58 for (int i = 0; i < tess.numPts(); ++i) { | |
| 59 *((SkPoint*)((intptr_t)verts + i * vertexStride)) = tess.point(i); | |
| 60 } | |
| 61 | |
| 62 // Make 'verts' point to the colors | |
| 63 verts += sizeof(SkPoint); | |
| 64 for (int i = 0; i < tess.numPts(); ++i) { | |
| 65 SkASSERT(tess.depth(i) >= -0.5f && tess.depth(i) <= 0.5f); | |
| 66 if (tweakAlphaForCoverage) { | |
| 67 SkASSERT(SkScalarRoundToInt(255.0f * (tess.depth(i) + 0.5f)) <= 255) ; | |
| 68 unsigned scale = SkScalarRoundToInt(255.0f * (tess.depth(i) + 0.5f)) ; | |
| 69 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, s cale); | |
| 70 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor; | |
| 71 } else { | |
| 72 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color; | |
| 73 *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor) ) = | |
| 74 tess.depth(i ) + 0.5f; | |
| 75 } | |
| 76 } | |
| 77 | |
| 78 for (int i = 0; i < tess.numIndices(); ++i) { | |
| 79 idxs[i] = tess.index(i) + firstIndex; | |
| 80 } | |
| 81 } | |
| 82 | |
| 83 static const GrGeometryProcessor* create_fill_gp(bool tweakAlphaForCoverage, | |
| 84 const SkMatrix& localMatrix, | |
| 85 bool usesLocalCoords, | |
| 86 bool coverageIgnored) { | |
| 87 uint32_t flags = GrDefaultGeoProcFactory::kColor_GPType; | |
| 88 if (!tweakAlphaForCoverage) { | |
| 89 flags |= GrDefaultGeoProcFactory::kCoverage_GPType; | |
| 90 } | |
| 91 | |
| 92 return GrDefaultGeoProcFactory::Create(flags, GrColor_WHITE, usesLocalCoords , coverageIgnored, | |
| 93 SkMatrix::I(), localMatrix); | |
| 94 } | |
| 95 | |
| 96 class AAFlatteningConvexPathBatch : public GrBatch { | |
| 97 public: | |
| 98 struct Geometry { | |
| 99 GrColor fColor; | |
| 100 SkMatrix fViewMatrix; | |
| 101 SkPath fPath; | |
| 102 }; | |
| 103 | |
| 104 static GrBatch* Create(const Geometry& geometry) { | |
| 105 return SkNEW_ARGS(AAFlatteningConvexPathBatch, (geometry)); | |
| 106 } | |
| 107 | |
| 108 const char* name() const override { return "AAConvexBatch"; } | |
| 109 | |
| 110 void getInvariantOutputColor(GrInitInvariantOutput* out) const override { | |
| 111 // When this is called on a batch, there is only one geometry bundle | |
| 112 out->setKnownFourComponents(fGeoData[0].fColor); | |
| 113 } | |
| 114 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override { | |
| 115 out->setUnknownSingleComponent(); | |
| 116 } | |
| 117 | |
| 118 void initBatchTracker(const GrPipelineInfo& init) override { | |
| 119 // Handle any color overrides | |
| 120 if (init.fColorIgnored) { | |
| 121 fGeoData[0].fColor = GrColor_ILLEGAL; | |
| 122 } else if (GrColor_ILLEGAL != init.fOverrideColor) { | |
| 123 fGeoData[0].fColor = init.fOverrideColor; | |
| 124 } | |
| 125 | |
| 126 // setup batch properties | |
| 127 fBatch.fColorIgnored = init.fColorIgnored; | |
| 128 fBatch.fColor = fGeoData[0].fColor; | |
| 129 fBatch.fUsesLocalCoords = init.fUsesLocalCoords; | |
| 130 fBatch.fCoverageIgnored = init.fCoverageIgnored; | |
| 131 fBatch.fLinesOnly = SkPath::kLine_SegmentMask == fGeoData[0].fPath.getSe gmentMasks(); | |
| 132 fBatch.fCanTweakAlphaForCoverage = init.fCanTweakAlphaForCoverage; | |
| 133 } | |
| 134 | |
| 135 void draw(GrBatchTarget* batchTarget, const GrPipeline* pipeline, int vertex Count, | |
| 136 size_t vertexStride, void* vertices, int indexCount, uint16_t* indic es) { | |
| 137 if (vertexCount == 0 || indexCount == 0) { | |
| 138 return; | |
| 139 } | |
| 140 const GrVertexBuffer* vertexBuffer; | |
| 141 GrVertices info; | |
| 142 int firstVertex; | |
| 143 void* verts = batchTarget->makeVertSpace(vertexStride, vertexCount, &ver texBuffer, | |
| 144 &firstVertex); | |
| 145 if (!verts) { | |
| 146 SkDebugf("Could not allocate vertices\n"); | |
| 147 return; | |
| 148 } | |
| 149 memcpy(verts, vertices, vertexCount * vertexStride); | |
| 150 | |
| 151 const GrIndexBuffer* indexBuffer; | |
| 152 int firstIndex; | |
| 153 uint16_t* idxs = batchTarget->makeIndexSpace(indexCount, &indexBuffer, & firstIndex); | |
| 154 if (!idxs) { | |
| 155 SkDebugf("Could not allocate indices\n"); | |
| 156 return; | |
| 157 } | |
| 158 memcpy(idxs, indices, indexCount * sizeof(uint16_t)); | |
| 159 info.initIndexed(kTriangles_GrPrimitiveType, vertexBuffer, indexBuffer, firstVertex, | |
| 160 firstIndex, vertexCount, indexCount); | |
| 161 batchTarget->draw(info); | |
| 162 } | |
| 163 | |
| 164 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline ) override { | |
| 165 bool canTweakAlphaForCoverage = this->canTweakAlphaForCoverage(); | |
| 166 | |
| 167 SkMatrix invert; | |
| 168 if (this->usesLocalCoords() && !this->viewMatrix().invert(&invert)) { | |
| 169 SkDebugf("Could not invert viewmatrix\n"); | |
| 170 return; | |
| 171 } | |
| 172 | |
| 173 // Setup GrGeometryProcessor | |
| 174 SkAutoTUnref<const GrGeometryProcessor> gp( | |
| 175 create_fill_gp(canTweakAlphaForC overage, invert, | |
| 176 this->usesLocalCo ords(), | |
| 177 this->coverageIgn ored())); | |
| 178 | |
| 179 batchTarget->initDraw(gp, pipeline); | |
| 180 | |
| 181 size_t vertexStride = gp->getVertexStride(); | |
| 182 | |
| 183 SkASSERT(canTweakAlphaForCoverage ? | |
| 184 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAt tr) : | |
| 185 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorCo verageAttr)); | |
| 186 | |
| 187 GrAAFlatteningConvexTessellator tess; | |
| 188 | |
| 189 int instanceCount = fGeoData.count(); | |
| 190 | |
| 191 int vertexCount = 0; | |
| 192 int indexCount = 0; | |
| 193 int maxVertices = DEFAULT_BUFFER_SIZE; | |
| 194 int maxIndices = DEFAULT_BUFFER_SIZE; | |
| 195 uint8_t* vertices = (uint8_t*) malloc(maxVertices * vertexStride); | |
| 196 uint16_t* indices = (uint16_t*) malloc(maxIndices * sizeof(uint16_t)); | |
| 197 for (int i = 0; i < instanceCount; i++) { | |
| 198 tess.rewind(); | |
| 199 | |
| 200 Geometry& args = fGeoData[i]; | |
| 201 | |
| 202 if (!tess.tessellate(args.fViewMatrix, args.fPath)) { | |
| 203 continue; | |
| 204 } | |
| 205 | |
| 206 #define MAX(a, b) (a > b ? a : b) | |
|
bsalomon
2015/05/27 17:11:07
There is an SkTMax
ethannicholas
2015/05/27 19:22:30
Done.
| |
| 207 | |
| 208 int currentIndices = tess.numIndices(); | |
| 209 SkASSERT(currentIndices <= UINT16_MAX); | |
| 210 if (indexCount + currentIndices > UINT16_MAX) { | |
| 211 // if we added the current instance, we would overflow the indic es we can store in a | |
| 212 // uint16_t. Draw what we've got so far and reset. | |
| 213 draw(batchTarget, pipeline, vertexCount, vertexStride, vertices, indexCount, | |
| 214 indices); | |
| 215 vertexCount = 0; | |
| 216 indexCount = 0; | |
| 217 } | |
| 218 int currentVertices = tess.numPts(); | |
| 219 if (vertexCount + currentVertices > maxVertices) { | |
| 220 maxVertices = MAX(vertexCount + currentVertices, maxVertices * 2 ); | |
| 221 vertices = (uint8_t*) realloc(vertices, maxVertices * vertexStri de); | |
| 222 } | |
| 223 if (indexCount + currentIndices > maxIndices) { | |
| 224 maxIndices = MAX(indexCount + currentIndices, maxIndices * 2); | |
| 225 indices = (uint16_t*) realloc(indices, maxIndices * sizeof(uint1 6_t)); | |
| 226 } | |
| 227 | |
| 228 #undef MAX | |
| 229 | |
| 230 extract_verts(tess, vertices + vertexStride * vertexCount, vertexStr ide, args.fColor, | |
| 231 vertexCount, indices + indexCount, canTweakAlphaForCoverage) ; | |
| 232 vertexCount += currentVertices; | |
| 233 indexCount += currentIndices; | |
| 234 } | |
| 235 draw(batchTarget, pipeline, vertexCount, vertexStride, vertices, indexCo unt, indices); | |
| 236 free(vertices); | |
| 237 free(indices); | |
| 238 } | |
| 239 | |
| 240 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; } | |
| 241 | |
| 242 private: | |
| 243 AAFlatteningConvexPathBatch(const Geometry& geometry) { | |
| 244 this->initClassID<AAFlatteningConvexPathBatch>(); | |
| 245 fGeoData.push_back(geometry); | |
| 246 | |
| 247 // compute bounds | |
| 248 fBounds = geometry.fPath.getBounds(); | |
| 249 geometry.fViewMatrix.mapRect(&fBounds); | |
| 250 } | |
| 251 | |
| 252 bool onCombineIfPossible(GrBatch* t) override { | |
| 253 AAFlatteningConvexPathBatch* that = t->cast<AAFlatteningConvexPathBatch> (); | |
| 254 | |
| 255 SkASSERT(this->usesLocalCoords() == that->usesLocalCoords()); | |
| 256 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->vi ewMatrix())) { | |
| 257 return false; | |
| 258 } | |
| 259 | |
| 260 // In the event of two batches, one who can tweak, one who cannot, we ju st fall back to | |
| 261 // not tweaking | |
| 262 if (this->canTweakAlphaForCoverage() != that->canTweakAlphaForCoverage() ) { | |
| 263 fBatch.fCanTweakAlphaForCoverage = false; | |
| 264 } | |
| 265 | |
| 266 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin()) ; | |
| 267 this->joinBounds(that->bounds()); | |
| 268 return true; | |
| 269 } | |
| 270 | |
| 271 GrColor color() const { return fBatch.fColor; } | |
| 272 bool linesOnly() const { return fBatch.fLinesOnly; } | |
| 273 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } | |
| 274 bool canTweakAlphaForCoverage() const { return fBatch.fCanTweakAlphaForCover age; } | |
| 275 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; } | |
| 276 bool coverageIgnored() const { return fBatch.fCoverageIgnored; } | |
| 277 | |
| 278 struct BatchTracker { | |
| 279 GrColor fColor; | |
| 280 bool fUsesLocalCoords; | |
| 281 bool fColorIgnored; | |
| 282 bool fCoverageIgnored; | |
| 283 bool fLinesOnly; | |
| 284 bool fCanTweakAlphaForCoverage; | |
| 285 }; | |
| 286 | |
| 287 BatchTracker fBatch; | |
| 288 SkSTArray<1, Geometry, true> fGeoData; | |
| 289 }; | |
| 290 | |
| 291 bool GrAAFlatteningConvexPathRenderer::onDrawPath(GrDrawTarget* target, | |
| 292 GrPipelineBuilder* pipelineBuilder, | |
| 293 GrColor color, | |
| 294 const SkMatrix& vm, | |
| 295 const SkPath& path, | |
| 296 const GrStrokeInfo&, | |
| 297 bool antiAlias) { | |
| 298 if (path.isEmpty()) { | |
| 299 return true; | |
| 300 } | |
| 301 AAFlatteningConvexPathBatch::Geometry geometry; | |
| 302 geometry.fColor = color; | |
| 303 geometry.fViewMatrix = vm; | |
| 304 geometry.fPath = path; | |
| 305 | |
| 306 SkAutoTUnref<GrBatch> batch(AAFlatteningConvexPathBatch::Create(geometry)); | |
| 307 target->drawBatch(pipelineBuilder, batch); | |
| 308 | |
| 309 return true; | |
| 310 } | |
| 311 | |
| 312 //////////////////////////////////////////////////////////////////////////////// /////////////////// | |
| 313 | |
| 314 #ifdef GR_TEST_UTILS | |
| 315 | |
| 316 BATCH_TEST_DEFINE(AAFlatteningConvexPathBatch) { | |
| 317 AAFlatteningConvexPathBatch::Geometry geometry; | |
| 318 geometry.fColor = GrRandomColor(random); | |
| 319 geometry.fViewMatrix = GrTest::TestMatrixInvertible(random); | |
| 320 geometry.fPath = GrTest::TestPathConvex(random); | |
| 321 | |
| 322 return AAFlatteningConvexPathBatch::Create(geometry); | |
| 323 } | |
| 324 | |
| 325 #endif | |
| OLD | NEW |