Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 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 "GrAADistanceFieldPathRenderer.h" | 8 #include "GrAADistanceFieldPathRenderer.h" |
| 9 | 9 |
| 10 #include "GrBatchFlushState.h" | 10 #include "GrBatchFlushState.h" |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 24 | 24 |
| 25 #define ATLAS_TEXTURE_WIDTH 2048 | 25 #define ATLAS_TEXTURE_WIDTH 2048 |
| 26 #define ATLAS_TEXTURE_HEIGHT 2048 | 26 #define ATLAS_TEXTURE_HEIGHT 2048 |
| 27 #define PLOT_WIDTH 512 | 27 #define PLOT_WIDTH 512 |
| 28 #define PLOT_HEIGHT 256 | 28 #define PLOT_HEIGHT 256 |
| 29 | 29 |
| 30 #define NUM_PLOTS_X (ATLAS_TEXTURE_WIDTH / PLOT_WIDTH) | 30 #define NUM_PLOTS_X (ATLAS_TEXTURE_WIDTH / PLOT_WIDTH) |
| 31 #define NUM_PLOTS_Y (ATLAS_TEXTURE_HEIGHT / PLOT_HEIGHT) | 31 #define NUM_PLOTS_Y (ATLAS_TEXTURE_HEIGHT / PLOT_HEIGHT) |
| 32 | 32 |
| 33 #ifdef DF_PATH_TRACKING | 33 #ifdef DF_PATH_TRACKING |
| 34 static int g_NumCachedPaths = 0; | 34 static int g_NumCachedShapes = 0; |
| 35 static int g_NumFreedPaths = 0; | 35 static int g_NumFreedShapes = 0; |
| 36 #endif | 36 #endif |
| 37 | 37 |
| 38 // mip levels | 38 // mip levels |
| 39 static const int kSmallMIP = 32; | 39 static const int kSmallMIP = 32; |
| 40 static const int kMediumMIP = 73; | 40 static const int kMediumMIP = 73; |
| 41 static const int kLargeMIP = 162; | 41 static const int kLargeMIP = 162; |
| 42 | 42 |
| 43 // Callback to clear out internal path cache when eviction occurs | 43 // Callback to clear out internal path cache when eviction occurs |
| 44 void GrAADistanceFieldPathRenderer::HandleEviction(GrBatchAtlas::AtlasID id, voi d* pr) { | 44 void GrAADistanceFieldPathRenderer::HandleEviction(GrBatchAtlas::AtlasID id, voi d* pr) { |
| 45 GrAADistanceFieldPathRenderer* dfpr = (GrAADistanceFieldPathRenderer*)pr; | 45 GrAADistanceFieldPathRenderer* dfpr = (GrAADistanceFieldPathRenderer*)pr; |
| 46 // remove any paths that use this plot | 46 // remove any paths that use this plot |
| 47 PathDataList::Iter iter; | 47 ShapeDataList::Iter iter; |
| 48 iter.init(dfpr->fPathList, PathDataList::Iter::kHead_IterStart); | 48 iter.init(dfpr->fShapeList, ShapeDataList::Iter::kHead_IterStart); |
| 49 PathData* pathData; | 49 ShapeData* shapeData; |
| 50 while ((pathData = iter.get())) { | 50 while ((shapeData = iter.get())) { |
| 51 iter.next(); | 51 iter.next(); |
| 52 if (id == pathData->fID) { | 52 if (id == shapeData->fID) { |
| 53 dfpr->fPathCache.remove(pathData->fKey); | 53 dfpr->fShapeCache.remove(shapeData->fKey); |
| 54 dfpr->fPathList.remove(pathData); | 54 dfpr->fShapeList.remove(shapeData); |
| 55 delete pathData; | 55 delete shapeData; |
| 56 #ifdef DF_PATH_TRACKING | 56 #ifdef DF_PATH_TRACKING |
| 57 ++g_NumFreedPaths; | 57 ++g_NumFreedPaths; |
| 58 #endif | 58 #endif |
| 59 } | 59 } |
| 60 } | 60 } |
| 61 } | 61 } |
| 62 | 62 |
| 63 //////////////////////////////////////////////////////////////////////////////// | 63 //////////////////////////////////////////////////////////////////////////////// |
| 64 GrAADistanceFieldPathRenderer::GrAADistanceFieldPathRenderer() : fAtlas(nullptr) {} | 64 GrAADistanceFieldPathRenderer::GrAADistanceFieldPathRenderer() : fAtlas(nullptr) {} |
| 65 | 65 |
| 66 GrAADistanceFieldPathRenderer::~GrAADistanceFieldPathRenderer() { | 66 GrAADistanceFieldPathRenderer::~GrAADistanceFieldPathRenderer() { |
| 67 PathDataList::Iter iter; | 67 ShapeDataList::Iter iter; |
| 68 iter.init(fPathList, PathDataList::Iter::kHead_IterStart); | 68 iter.init(fShapeList, ShapeDataList::Iter::kHead_IterStart); |
| 69 PathData* pathData; | 69 ShapeData* shapeData; |
| 70 while ((pathData = iter.get())) { | 70 while ((shapeData = iter.get())) { |
| 71 iter.next(); | 71 iter.next(); |
| 72 fPathList.remove(pathData); | 72 fShapeList.remove(shapeData); |
| 73 delete pathData; | 73 delete shapeData; |
| 74 } | 74 } |
| 75 delete fAtlas; | 75 delete fAtlas; |
| 76 | 76 |
| 77 #ifdef DF_PATH_TRACKING | 77 #ifdef DF_PATH_TRACKING |
| 78 SkDebugf("Cached paths: %d, freed paths: %d\n", g_NumCachedPaths, g_NumFreed Paths); | 78 SkDebugf("Cached shapes: %d, freed shapes: %d\n", g_NumCachedShapes, g_NumFr eedShapes); |
| 79 #endif | 79 #endif |
| 80 } | 80 } |
| 81 | 81 |
| 82 //////////////////////////////////////////////////////////////////////////////// | 82 //////////////////////////////////////////////////////////////////////////////// |
| 83 bool GrAADistanceFieldPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) c onst { | 83 bool GrAADistanceFieldPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) c onst { |
| 84 // We don't currently apply the dash or factor it into the DF key. (skbug.co m/5082) | 84 if (!args.fShaderCaps->shaderDerivativeSupport()) { |
| 85 if (args.fShape->style().pathEffect()) { | |
| 86 return false; | 85 return false; |
| 87 } | 86 } |
| 87 // If the shape has no key then we won't get any reuse. | |
| 88 if (!args.fShape->hasUnstyledKey()) { | |
| 89 return false; | |
| 90 } | |
| 91 if (args.fShape->style().applies()) { | |
| 92 // This may come back around after the style has been applied. | |
| 93 return false; | |
| 94 } | |
| 95 // This does non-inverse antialiased fills. | |
| 88 // TODO: Support inverse fill | 96 // TODO: Support inverse fill |
| 89 if (!args.fShaderCaps->shaderDerivativeSupport() || !args.fAntiAlias || | 97 if (!args.fAntiAlias || !args.fShape->style().isSimpleFill() ||args.fShape-> inverseFilled()) { |
|
egdaniel
2016/06/27 13:16:58
space after ||
bsalomon
2016/06/27 13:37:52
Done.
| |
| 90 args.fShape->style().isSimpleHairline() || args.fShape->mayBeInverseFill edAfterStyling() || | |
| 91 !args.fShape->hasUnstyledKey()) { | |
| 92 return false; | 98 return false; |
| 93 } | 99 } |
| 94 | 100 |
| 95 // currently don't support perspective | 101 // currently don't support perspective |
| 96 if (args.fViewMatrix->hasPerspective()) { | 102 if (args.fViewMatrix->hasPerspective()) { |
| 97 return false; | 103 return false; |
| 98 } | 104 } |
| 99 | 105 |
| 100 // only support paths with bounds within kMediumMIP by kMediumMIP, | 106 // only support paths with bounds within kMediumMIP by kMediumMIP, |
| 101 // scaled to have bounds within 2.0f*kLargeMIP by 2.0f*kLargeMIP | 107 // scaled to have bounds within 2.0f*kLargeMIP by 2.0f*kLargeMIP |
| 102 // the goal is to accelerate rendering of lots of small paths that may be sc aling | 108 // the goal is to accelerate rendering of lots of small paths that may be sc aling |
| 103 SkScalar maxScale = args.fViewMatrix->getMaxScale(); | 109 SkScalar maxScale = args.fViewMatrix->getMaxScale(); |
| 104 SkRect bounds; | 110 SkRect bounds; |
| 105 args.fShape->styledBounds(&bounds); | 111 args.fShape->styledBounds(&bounds); |
| 106 SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height()); | 112 SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height()); |
| 107 | 113 |
| 108 return maxDim <= kMediumMIP && maxDim * maxScale <= 2.0f*kLargeMIP; | 114 return maxDim <= kMediumMIP && maxDim * maxScale <= 2.0f*kLargeMIP; |
| 109 } | 115 } |
| 110 | 116 |
| 111 //////////////////////////////////////////////////////////////////////////////// | 117 //////////////////////////////////////////////////////////////////////////////// |
| 112 | 118 |
| 113 // padding around path bounds to allow for antialiased pixels | 119 // padding around path bounds to allow for antialiased pixels |
| 114 static const SkScalar kAntiAliasPad = 1.0f; | 120 static const SkScalar kAntiAliasPad = 1.0f; |
| 115 | 121 |
| 116 class AADistanceFieldPathBatch : public GrVertexBatch { | 122 class AADistanceFieldPathBatch : public GrVertexBatch { |
| 117 public: | 123 public: |
| 118 DEFINE_BATCH_CLASS_ID | 124 DEFINE_BATCH_CLASS_ID |
| 119 | 125 |
| 120 typedef GrAADistanceFieldPathRenderer::PathData PathData; | 126 typedef GrAADistanceFieldPathRenderer::ShapeData ShapeData; |
| 121 typedef SkTDynamicHash<PathData, PathData::Key> PathCache; | 127 typedef SkTDynamicHash<ShapeData, ShapeData::Key> ShapeCache; |
| 122 typedef GrAADistanceFieldPathRenderer::PathDataList PathDataList; | 128 typedef GrAADistanceFieldPathRenderer::ShapeDataList ShapeDataList; |
| 123 | 129 |
| 124 struct Geometry { | 130 struct Geometry { |
| 125 Geometry(const SkStrokeRec& stroke) : fStroke(stroke) { | 131 GrShape fShape; |
| 126 if (!stroke.needToApply()) { | |
| 127 // purify unused values to ensure binary equality | |
| 128 fStroke.setStrokeParams(SkPaint::kDefault_Cap, SkPaint::kDefault _Join, | |
| 129 SkIntToScalar(4)); | |
| 130 if (fStroke.getWidth() < 0) { | |
| 131 fStroke.setStrokeStyle(-1.0f); | |
| 132 } | |
| 133 } | |
| 134 } | |
| 135 SkPath fPath; | |
| 136 // The unique ID of the path involved in this draw. This may be differen t than the ID | |
| 137 // in fPath since that path may have resulted from a SkStrokeRec::applyT oPath call. | |
| 138 uint32_t fGenID; | |
| 139 SkStrokeRec fStroke; | |
| 140 GrColor fColor; | 132 GrColor fColor; |
| 141 bool fAntiAlias; | 133 bool fAntiAlias; |
| 142 }; | 134 }; |
| 143 | 135 |
| 144 static GrDrawBatch* Create(const Geometry& geometry, const SkMatrix& viewMat rix, | 136 static GrDrawBatch* Create(const Geometry& geometry, const SkMatrix& viewMat rix, |
| 145 GrBatchAtlas* atlas, PathCache* pathCache, PathDa taList* pathList, | 137 GrBatchAtlas* atlas, ShapeCache* shapeCache, |
| 146 bool gammaCorrect) { | 138 ShapeDataList* shapeList, bool gammaCorrect) { |
| 147 return new AADistanceFieldPathBatch(geometry, viewMatrix, atlas, pathCac he, pathList, | 139 return new AADistanceFieldPathBatch(geometry, viewMatrix, atlas, shapeCa che, shapeList, |
| 148 gammaCorrect); | 140 gammaCorrect); |
| 149 } | 141 } |
| 150 | 142 |
| 151 const char* name() const override { return "AADistanceFieldPathBatch"; } | 143 const char* name() const override { return "AADistanceFieldPathBatch"; } |
| 152 | 144 |
| 153 void computePipelineOptimizations(GrInitInvariantOutput* color, | 145 void computePipelineOptimizations(GrInitInvariantOutput* color, |
| 154 GrInitInvariantOutput* coverage, | 146 GrInitInvariantOutput* coverage, |
| 155 GrBatchToXPOverrides* overrides) const ove rride { | 147 GrBatchToXPOverrides* overrides) const ove rride { |
| 156 color->setKnownFourComponents(fGeoData[0].fColor); | 148 color->setKnownFourComponents(fGeoData[0].fColor); |
| 157 coverage->setUnknownSingleComponent(); | 149 coverage->setUnknownSingleComponent(); |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 222 SkDebugf("Could not allocate vertices\n"); | 214 SkDebugf("Could not allocate vertices\n"); |
| 223 return; | 215 return; |
| 224 } | 216 } |
| 225 | 217 |
| 226 flushInfo.fInstancesToFlush = 0; | 218 flushInfo.fInstancesToFlush = 0; |
| 227 for (int i = 0; i < instanceCount; i++) { | 219 for (int i = 0; i < instanceCount; i++) { |
| 228 const Geometry& args = fGeoData[i]; | 220 const Geometry& args = fGeoData[i]; |
| 229 | 221 |
| 230 // get mip level | 222 // get mip level |
| 231 SkScalar maxScale = this->viewMatrix().getMaxScale(); | 223 SkScalar maxScale = this->viewMatrix().getMaxScale(); |
| 232 const SkRect& bounds = args.fPath.getBounds(); | 224 const SkRect& bounds = args.fShape.bounds(); |
| 233 SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height()); | 225 SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height()); |
| 234 SkScalar size = maxScale * maxDim; | 226 SkScalar size = maxScale * maxDim; |
| 235 uint32_t desiredDimension; | 227 uint32_t desiredDimension; |
| 236 if (size <= kSmallMIP) { | 228 if (size <= kSmallMIP) { |
| 237 desiredDimension = kSmallMIP; | 229 desiredDimension = kSmallMIP; |
| 238 } else if (size <= kMediumMIP) { | 230 } else if (size <= kMediumMIP) { |
| 239 desiredDimension = kMediumMIP; | 231 desiredDimension = kMediumMIP; |
| 240 } else { | 232 } else { |
| 241 desiredDimension = kLargeMIP; | 233 desiredDimension = kLargeMIP; |
| 242 } | 234 } |
| 243 | 235 |
| 244 // check to see if path is cached | 236 // check to see if path is cached |
| 245 PathData::Key key(args.fGenID, desiredDimension, args.fStroke); | 237 ShapeData::Key key(args.fShape, desiredDimension); |
| 246 PathData* pathData = fPathCache->find(key); | 238 ShapeData* shapeData = fShapeCache->find(key); |
| 247 if (nullptr == pathData || !atlas->hasID(pathData->fID)) { | 239 if (nullptr == shapeData || !atlas->hasID(shapeData->fID)) { |
| 248 // Remove the stale cache entry | 240 // Remove the stale cache entry |
| 249 if (pathData) { | 241 if (shapeData) { |
| 250 fPathCache->remove(pathData->fKey); | 242 fShapeCache->remove(shapeData->fKey); |
| 251 fPathList->remove(pathData); | 243 fShapeList->remove(shapeData); |
| 252 delete pathData; | 244 delete shapeData; |
| 253 } | 245 } |
| 254 SkScalar scale = desiredDimension/maxDim; | 246 SkScalar scale = desiredDimension/maxDim; |
| 255 pathData = new PathData; | 247 shapeData = new ShapeData; |
| 256 if (!this->addPathToAtlas(target, | 248 if (!this->addPathToAtlas(target, |
| 257 &flushInfo, | 249 &flushInfo, |
| 258 atlas, | 250 atlas, |
| 259 pathData, | 251 shapeData, |
| 260 args.fPath, | 252 args.fShape, |
| 261 args.fGenID, | |
| 262 args.fStroke, | |
| 263 args.fAntiAlias, | 253 args.fAntiAlias, |
| 264 desiredDimension, | 254 desiredDimension, |
| 265 scale)) { | 255 scale)) { |
| 266 SkDebugf("Can't rasterize path\n"); | 256 SkDebugf("Can't rasterize path\n"); |
| 267 return; | 257 return; |
| 268 } | 258 } |
| 269 } | 259 } |
| 270 | 260 |
| 271 atlas->setLastUseToken(pathData->fID, target->nextDrawToken()); | 261 atlas->setLastUseToken(shapeData->fID, target->nextDrawToken()); |
| 272 | 262 |
| 273 // Now set vertices | 263 // Now set vertices |
| 274 intptr_t offset = reinterpret_cast<intptr_t>(vertices); | 264 intptr_t offset = reinterpret_cast<intptr_t>(vertices); |
| 275 offset += i * kVerticesPerQuad * vertexStride; | 265 offset += i * kVerticesPerQuad * vertexStride; |
| 276 this->writePathVertices(target, | 266 this->writePathVertices(target, |
| 277 atlas, | 267 atlas, |
| 278 offset, | 268 offset, |
| 279 args.fColor, | 269 args.fColor, |
| 280 vertexStride, | 270 vertexStride, |
| 281 this->viewMatrix(), | 271 this->viewMatrix(), |
| 282 args.fPath, | 272 args.fShape, |
| 283 pathData); | 273 shapeData); |
| 284 flushInfo.fInstancesToFlush++; | 274 flushInfo.fInstancesToFlush++; |
| 285 } | 275 } |
| 286 | 276 |
| 287 this->flush(target, &flushInfo); | 277 this->flush(target, &flushInfo); |
| 288 } | 278 } |
| 289 | 279 |
| 290 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; } | |
| 291 | |
| 292 AADistanceFieldPathBatch(const Geometry& geometry, | 280 AADistanceFieldPathBatch(const Geometry& geometry, |
| 293 const SkMatrix& viewMatrix, | 281 const SkMatrix& viewMatrix, |
| 294 GrBatchAtlas* atlas, | 282 GrBatchAtlas* atlas, |
| 295 PathCache* pathCache, PathDataList* pathList, | 283 ShapeCache* shapeCache, ShapeDataList* shapeList, |
| 296 bool gammaCorrect) | 284 bool gammaCorrect) |
| 297 : INHERITED(ClassID()) { | 285 : INHERITED(ClassID()) { |
| 286 SkASSERT(geometry.fShape.hasUnstyledKey()); | |
| 298 fBatch.fViewMatrix = viewMatrix; | 287 fBatch.fViewMatrix = viewMatrix; |
| 299 fGeoData.push_back(geometry); | 288 fGeoData.push_back(geometry); |
| 289 SkASSERT(fGeoData[0].fShape.hasUnstyledKey()); | |
| 300 | 290 |
| 301 fAtlas = atlas; | 291 fAtlas = atlas; |
| 302 fPathCache = pathCache; | 292 fShapeCache = shapeCache; |
| 303 fPathList = pathList; | 293 fShapeList = shapeList; |
| 304 fGammaCorrect = gammaCorrect; | 294 fGammaCorrect = gammaCorrect; |
| 305 | 295 |
| 306 // Compute bounds | 296 // Compute bounds |
| 307 fBounds = geometry.fPath.getBounds(); | 297 fBounds = geometry.fShape.bounds(); |
| 308 viewMatrix.mapRect(&fBounds); | 298 viewMatrix.mapRect(&fBounds); |
| 309 } | 299 } |
| 310 | 300 |
| 311 bool addPathToAtlas(GrVertexBatch::Target* target, | 301 bool addPathToAtlas(GrVertexBatch::Target* target, |
| 312 FlushInfo* flushInfo, | 302 FlushInfo* flushInfo, |
| 313 GrBatchAtlas* atlas, | 303 GrBatchAtlas* atlas, |
| 314 PathData* pathData, | 304 ShapeData* shapeData, |
| 315 const SkPath& path, | 305 const GrShape& shape, |
| 316 uint32_t genID, | |
| 317 const SkStrokeRec& stroke, | |
| 318 bool antiAlias, | 306 bool antiAlias, |
| 319 uint32_t dimension, | 307 uint32_t dimension, |
| 320 SkScalar scale) const { | 308 SkScalar scale) const { |
| 321 const SkRect& bounds = path.getBounds(); | 309 const SkRect& bounds = shape.bounds(); |
| 322 | 310 |
| 323 // generate bounding rect for bitmap draw | 311 // generate bounding rect for bitmap draw |
| 324 SkRect scaledBounds = bounds; | 312 SkRect scaledBounds = bounds; |
| 325 // scale to mip level size | 313 // scale to mip level size |
| 326 scaledBounds.fLeft *= scale; | 314 scaledBounds.fLeft *= scale; |
| 327 scaledBounds.fTop *= scale; | 315 scaledBounds.fTop *= scale; |
| 328 scaledBounds.fRight *= scale; | 316 scaledBounds.fRight *= scale; |
| 329 scaledBounds.fBottom *= scale; | 317 scaledBounds.fBottom *= scale; |
| 330 // move the origin to an integer boundary (gives better results) | 318 // move the origin to an integer boundary (gives better results) |
| 331 SkScalar dx = SkScalarFraction(scaledBounds.fLeft); | 319 SkScalar dx = SkScalarFraction(scaledBounds.fLeft); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 368 | 356 |
| 369 SkDraw draw; | 357 SkDraw draw; |
| 370 sk_bzero(&draw, sizeof(draw)); | 358 sk_bzero(&draw, sizeof(draw)); |
| 371 | 359 |
| 372 SkRasterClip rasterClip; | 360 SkRasterClip rasterClip; |
| 373 rasterClip.setRect(devPathBounds); | 361 rasterClip.setRect(devPathBounds); |
| 374 draw.fRC = &rasterClip; | 362 draw.fRC = &rasterClip; |
| 375 draw.fMatrix = &drawMatrix; | 363 draw.fMatrix = &drawMatrix; |
| 376 draw.fDst = dst; | 364 draw.fDst = dst; |
| 377 | 365 |
| 366 SkPath path; | |
| 367 shape.asPath(&path); | |
| 378 draw.drawPathCoverage(path, paint); | 368 draw.drawPathCoverage(path, paint); |
| 379 | 369 |
| 380 // generate signed distance field | 370 // generate signed distance field |
| 381 devPathBounds.outset(SK_DistanceFieldPad, SK_DistanceFieldPad); | 371 devPathBounds.outset(SK_DistanceFieldPad, SK_DistanceFieldPad); |
| 382 width = devPathBounds.width(); | 372 width = devPathBounds.width(); |
| 383 height = devPathBounds.height(); | 373 height = devPathBounds.height(); |
| 384 // TODO We should really generate this directly into the plot somehow | 374 // TODO We should really generate this directly into the plot somehow |
| 385 SkAutoSMalloc<1024> dfStorage(width * height * sizeof(unsigned char)); | 375 SkAutoSMalloc<1024> dfStorage(width * height * sizeof(unsigned char)); |
| 386 | 376 |
| 387 // Generate signed distance field | 377 // Generate signed distance field |
| 388 SkGenerateDistanceFieldFromA8Image((unsigned char*)dfStorage.get(), | 378 SkGenerateDistanceFieldFromA8Image((unsigned char*)dfStorage.get(), |
| 389 (const unsigned char*)dst.addr(), | 379 (const unsigned char*)dst.addr(), |
| 390 dst.width(), dst.height(), dst.rowByt es()); | 380 dst.width(), dst.height(), dst.rowByt es()); |
| 391 | 381 |
| 392 // add to atlas | 382 // add to atlas |
| 393 SkIPoint16 atlasLocation; | 383 SkIPoint16 atlasLocation; |
| 394 GrBatchAtlas::AtlasID id; | 384 GrBatchAtlas::AtlasID id; |
| 395 bool success = atlas->addToAtlas(&id, target, width, height, dfStorage.g et(), | 385 bool success = atlas->addToAtlas(&id, target, width, height, dfStorage.g et(), |
| 396 &atlasLocation); | 386 &atlasLocation); |
| 397 if (!success) { | 387 if (!success) { |
| 398 this->flush(target, flushInfo); | 388 this->flush(target, flushInfo); |
| 399 | 389 |
| 400 SkDEBUGCODE(success =) atlas->addToAtlas(&id, target, width, height, | 390 SkDEBUGCODE(success =) atlas->addToAtlas(&id, target, width, height, |
| 401 dfStorage.get(), &atlasLoca tion); | 391 dfStorage.get(), &atlasLoca tion); |
| 402 SkASSERT(success); | 392 SkASSERT(success); |
| 403 | 393 |
| 404 } | 394 } |
| 405 | 395 |
| 406 // add to cache | 396 // add to cache |
| 407 pathData->fKey = PathData::Key(genID, dimension, stroke); | 397 shapeData->fKey.set(shape, dimension); |
| 408 pathData->fScale = scale; | 398 shapeData->fScale = scale; |
| 409 pathData->fID = id; | 399 shapeData->fID = id; |
| 410 // change the scaled rect to match the size of the inset distance field | 400 // change the scaled rect to match the size of the inset distance field |
| 411 scaledBounds.fRight = scaledBounds.fLeft + | 401 scaledBounds.fRight = scaledBounds.fLeft + |
| 412 SkIntToScalar(devPathBounds.width() - 2*SK_DistanceFieldInset); | 402 SkIntToScalar(devPathBounds.width() - 2*SK_DistanceFieldInset); |
| 413 scaledBounds.fBottom = scaledBounds.fTop + | 403 scaledBounds.fBottom = scaledBounds.fTop + |
| 414 SkIntToScalar(devPathBounds.height() - 2*SK_DistanceFieldInset); | 404 SkIntToScalar(devPathBounds.height() - 2*SK_DistanceFieldInset); |
| 415 // shift the origin to the correct place relative to the distance field | 405 // shift the origin to the correct place relative to the distance field |
| 416 // need to also restore the fractional translation | 406 // need to also restore the fractional translation |
| 417 scaledBounds.offset(-SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPa d + dx, | 407 scaledBounds.offset(-SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPa d + dx, |
| 418 -SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPa d + dy); | 408 -SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPa d + dy); |
| 419 pathData->fBounds = scaledBounds; | 409 shapeData->fBounds = scaledBounds; |
| 420 // origin we render from is inset from distance field edge | 410 // origin we render from is inset from distance field edge |
| 421 atlasLocation.fX += SK_DistanceFieldInset; | 411 atlasLocation.fX += SK_DistanceFieldInset; |
| 422 atlasLocation.fY += SK_DistanceFieldInset; | 412 atlasLocation.fY += SK_DistanceFieldInset; |
| 423 pathData->fAtlasLocation = atlasLocation; | 413 shapeData->fAtlasLocation = atlasLocation; |
| 424 | 414 |
| 425 fPathCache->add(pathData); | 415 fShapeCache->add(shapeData); |
| 426 fPathList->addToTail(pathData); | 416 fShapeList->addToTail(shapeData); |
| 427 #ifdef DF_PATH_TRACKING | 417 #ifdef DF_PATH_TRACKING |
| 428 ++g_NumCachedPaths; | 418 ++g_NumCachedPaths; |
| 429 #endif | 419 #endif |
| 430 return true; | 420 return true; |
| 431 } | 421 } |
| 432 | 422 |
| 433 void writePathVertices(GrDrawBatch::Target* target, | 423 void writePathVertices(GrDrawBatch::Target* target, |
| 434 GrBatchAtlas* atlas, | 424 GrBatchAtlas* atlas, |
| 435 intptr_t offset, | 425 intptr_t offset, |
| 436 GrColor color, | 426 GrColor color, |
| 437 size_t vertexStride, | 427 size_t vertexStride, |
| 438 const SkMatrix& viewMatrix, | 428 const SkMatrix& viewMatrix, |
| 439 const SkPath& path, | 429 const GrShape& shape, |
| 440 const PathData* pathData) const { | 430 const ShapeData* shapeData) const { |
| 441 GrTexture* texture = atlas->getTexture(); | 431 GrTexture* texture = atlas->getTexture(); |
| 442 | 432 |
| 443 SkScalar dx = pathData->fBounds.fLeft; | 433 SkScalar dx = shapeData->fBounds.fLeft; |
| 444 SkScalar dy = pathData->fBounds.fTop; | 434 SkScalar dy = shapeData->fBounds.fTop; |
| 445 SkScalar width = pathData->fBounds.width(); | 435 SkScalar width = shapeData->fBounds.width(); |
| 446 SkScalar height = pathData->fBounds.height(); | 436 SkScalar height = shapeData->fBounds.height(); |
| 447 | 437 |
| 448 SkScalar invScale = 1.0f / pathData->fScale; | 438 SkScalar invScale = 1.0f / shapeData->fScale; |
| 449 dx *= invScale; | 439 dx *= invScale; |
| 450 dy *= invScale; | 440 dy *= invScale; |
| 451 width *= invScale; | 441 width *= invScale; |
| 452 height *= invScale; | 442 height *= invScale; |
| 453 | 443 |
| 454 SkPoint* positions = reinterpret_cast<SkPoint*>(offset); | 444 SkPoint* positions = reinterpret_cast<SkPoint*>(offset); |
| 455 | 445 |
| 456 // vertex positions | 446 // vertex positions |
| 457 // TODO make the vertex attributes a struct | 447 // TODO make the vertex attributes a struct |
| 458 SkRect r = SkRect::MakeXYWH(dx, dy, width, height); | 448 SkRect r = SkRect::MakeXYWH(dx, dy, width, height); |
| 459 positions->setRectFan(r.left(), r.top(), r.right(), r.bottom(), vertexSt ride); | 449 positions->setRectFan(r.left(), r.top(), r.right(), r.bottom(), vertexSt ride); |
| 460 | 450 |
| 461 // colors | 451 // colors |
| 462 for (int i = 0; i < kVerticesPerQuad; i++) { | 452 for (int i = 0; i < kVerticesPerQuad; i++) { |
| 463 GrColor* colorPtr = (GrColor*)(offset + sizeof(SkPoint) + i * vertex Stride); | 453 GrColor* colorPtr = (GrColor*)(offset + sizeof(SkPoint) + i * vertex Stride); |
| 464 *colorPtr = color; | 454 *colorPtr = color; |
| 465 } | 455 } |
| 466 | 456 |
| 467 const SkScalar tx = SkIntToScalar(pathData->fAtlasLocation.fX); | 457 const SkScalar tx = SkIntToScalar(shapeData->fAtlasLocation.fX); |
| 468 const SkScalar ty = SkIntToScalar(pathData->fAtlasLocation.fY); | 458 const SkScalar ty = SkIntToScalar(shapeData->fAtlasLocation.fY); |
| 469 | 459 |
| 470 // vertex texture coords | 460 // vertex texture coords |
| 471 SkPoint* textureCoords = (SkPoint*)(offset + sizeof(SkPoint) + sizeof(Gr Color)); | 461 SkPoint* textureCoords = (SkPoint*)(offset + sizeof(SkPoint) + sizeof(Gr Color)); |
| 472 textureCoords->setRectFan(tx / texture->width(), | 462 textureCoords->setRectFan(tx / texture->width(), |
| 473 ty / texture->height(), | 463 ty / texture->height(), |
| 474 (tx + pathData->fBounds.width()) / texture->wi dth(), | 464 (tx + shapeData->fBounds.width()) / texture->w idth(), |
| 475 (ty + pathData->fBounds.height()) / texture-> height(), | 465 (ty + shapeData->fBounds.height()) / texture- >height(), |
| 476 vertexStride); | 466 vertexStride); |
| 477 } | 467 } |
| 478 | 468 |
| 479 void flush(GrVertexBatch::Target* target, FlushInfo* flushInfo) const { | 469 void flush(GrVertexBatch::Target* target, FlushInfo* flushInfo) const { |
| 480 GrMesh mesh; | 470 GrMesh mesh; |
| 481 int maxInstancesPerDraw = | 471 int maxInstancesPerDraw = |
| 482 static_cast<int>(flushInfo->fIndexBuffer->gpuMemorySize() / sizeof(u int16_t) / 6); | 472 static_cast<int>(flushInfo->fIndexBuffer->gpuMemorySize() / sizeof(u int16_t) / 6); |
| 483 mesh.initInstanced(kTriangles_GrPrimitiveType, flushInfo->fVertexBuffer, | 473 mesh.initInstanced(kTriangles_GrPrimitiveType, flushInfo->fVertexBuffer, |
| 484 flushInfo->fIndexBuffer, flushInfo->fVertexOffset, kVerticesPerQuad, | 474 flushInfo->fIndexBuffer, flushInfo->fVertexOffset, kVerticesPerQuad, |
| 485 kIndicesPerQuad, flushInfo->fInstancesToFlush, maxInstancesPerDraw); | 475 kIndicesPerQuad, flushInfo->fInstancesToFlush, maxInstancesPerDraw); |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 497 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pi peline(), | 487 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pi peline(), |
| 498 that->bounds(), caps)) { | 488 that->bounds(), caps)) { |
| 499 return false; | 489 return false; |
| 500 } | 490 } |
| 501 | 491 |
| 502 // TODO We can position on the cpu | 492 // TODO We can position on the cpu |
| 503 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) { | 493 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) { |
| 504 return false; | 494 return false; |
| 505 } | 495 } |
| 506 | 496 |
| 507 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin()) ; | 497 fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin()); |
| 508 this->joinBounds(that->bounds()); | 498 this->joinBounds(that->bounds()); |
| 509 return true; | 499 return true; |
| 510 } | 500 } |
| 511 | 501 |
| 512 struct BatchTracker { | 502 struct BatchTracker { |
| 513 SkMatrix fViewMatrix; | 503 SkMatrix fViewMatrix; |
| 514 bool fUsesLocalCoords; | 504 bool fUsesLocalCoords; |
| 515 bool fColorIgnored; | 505 bool fColorIgnored; |
| 516 bool fCoverageIgnored; | 506 bool fCoverageIgnored; |
| 517 }; | 507 }; |
| 518 | 508 |
| 519 BatchTracker fBatch; | 509 BatchTracker fBatch; |
| 520 SkSTArray<1, Geometry, true> fGeoData; | 510 SkSTArray<1, Geometry> fGeoData; |
| 521 GrBatchAtlas* fAtlas; | 511 GrBatchAtlas* fAtlas; |
| 522 PathCache* fPathCache; | 512 ShapeCache* fShapeCache; |
| 523 PathDataList* fPathList; | 513 ShapeDataList* fShapeList; |
| 524 bool fGammaCorrect; | 514 bool fGammaCorrect; |
| 525 | 515 |
| 526 typedef GrVertexBatch INHERITED; | 516 typedef GrVertexBatch INHERITED; |
| 527 }; | 517 }; |
| 528 | 518 |
| 529 bool GrAADistanceFieldPathRenderer::onDrawPath(const DrawPathArgs& args) { | 519 bool GrAADistanceFieldPathRenderer::onDrawPath(const DrawPathArgs& args) { |
| 530 GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(), | 520 GR_AUDIT_TRAIL_AUTO_FRAME(args.fDrawContext->auditTrail(), |
| 531 "GrAADistanceFieldPathRenderer::onDrawPath"); | 521 "GrAADistanceFieldPathRenderer::onDrawPath"); |
| 532 SkASSERT(!args.fDrawContext->isUnifiedMultisampled()); | 522 SkASSERT(!args.fDrawContext->isUnifiedMultisampled()); |
| 533 | 523 |
| 534 // we've already bailed on inverse filled paths, so this is safe | 524 // we've already bailed on inverse filled paths, so this is safe |
| 535 SkASSERT(!args.fShape->isEmpty()); | 525 SkASSERT(!args.fShape->isEmpty()); |
| 536 | 526 SkASSERT(args.fShape->hasUnstyledKey()); |
| 537 if (!fAtlas) { | 527 if (!fAtlas) { |
| 538 fAtlas = args.fResourceProvider->createAtlas(kAlpha_8_GrPixelConfig, | 528 fAtlas = args.fResourceProvider->createAtlas(kAlpha_8_GrPixelConfig, |
| 539 ATLAS_TEXTURE_WIDTH, ATLAS_ TEXTURE_HEIGHT, | 529 ATLAS_TEXTURE_WIDTH, ATLAS_ TEXTURE_HEIGHT, |
| 540 NUM_PLOTS_X, NUM_PLOTS_Y, | 530 NUM_PLOTS_X, NUM_PLOTS_Y, |
| 541 &GrAADistanceFieldPathRende rer::HandleEviction, | 531 &GrAADistanceFieldPathRende rer::HandleEviction, |
| 542 (void*)this); | 532 (void*)this); |
| 543 if (!fAtlas) { | 533 if (!fAtlas) { |
| 544 return false; | 534 return false; |
| 545 } | 535 } |
| 546 } | 536 } |
| 547 | 537 |
| 548 const GrStyle& style = args.fShape->style(); | 538 AADistanceFieldPathBatch::Geometry geometry; |
| 549 // It's ok to ignore style's path effect because canDrawPath filtered out pa th effects. | 539 geometry.fShape = *args.fShape; |
| 550 AADistanceFieldPathBatch::Geometry geometry(style.strokeRec()); | |
| 551 args.fShape->asPath(&geometry.fPath); | |
| 552 // Note: this is the generation ID of the _original_ path. When a new path i s | |
| 553 // generated due to stroking it is important that the original path's id is used | |
| 554 // for caching. | |
| 555 geometry.fGenID = geometry.fPath.getGenerationID(); | |
| 556 if (!style.isSimpleFill()) { | |
| 557 style.strokeRec().applyToPath(&geometry.fPath, geometry.fPath); | |
| 558 } | |
| 559 geometry.fColor = args.fColor; | 540 geometry.fColor = args.fColor; |
| 560 geometry.fAntiAlias = args.fAntiAlias; | 541 geometry.fAntiAlias = args.fAntiAlias; |
| 561 | 542 |
| 562 SkAutoTUnref<GrDrawBatch> batch(AADistanceFieldPathBatch::Create(geometry, | 543 SkAutoTUnref<GrDrawBatch> batch(AADistanceFieldPathBatch::Create(geometry, |
| 563 *args.fView Matrix, fAtlas, | 544 *args.fView Matrix, fAtlas, |
| 564 &fPathCache , &fPathList, | 545 &fShapeCach e, &fShapeList, |
| 565 args.fGamma Correct)); | 546 args.fGamma Correct)); |
| 566 | 547 |
| 567 GrPipelineBuilder pipelineBuilder(*args.fPaint); | 548 GrPipelineBuilder pipelineBuilder(*args.fPaint); |
| 568 pipelineBuilder.setUserStencil(args.fUserStencilSettings); | 549 pipelineBuilder.setUserStencil(args.fUserStencilSettings); |
| 569 | 550 |
| 570 args.fDrawContext->drawBatch(pipelineBuilder, *args.fClip, batch); | 551 args.fDrawContext->drawBatch(pipelineBuilder, *args.fClip, batch); |
| 571 | 552 |
| 572 return true; | 553 return true; |
| 573 } | 554 } |
| 574 | 555 |
| 575 //////////////////////////////////////////////////////////////////////////////// /////////////////// | 556 //////////////////////////////////////////////////////////////////////////////// /////////////////// |
| 576 | 557 |
| 577 #ifdef GR_TEST_UTILS | 558 #ifdef GR_TEST_UTILS |
| 578 | 559 |
| 579 struct PathTestStruct { | 560 struct PathTestStruct { |
| 580 typedef GrAADistanceFieldPathRenderer::PathCache PathCache; | 561 typedef GrAADistanceFieldPathRenderer::ShapeCache ShapeCache; |
| 581 typedef GrAADistanceFieldPathRenderer::PathData PathData; | 562 typedef GrAADistanceFieldPathRenderer::ShapeData ShapeData; |
| 582 typedef GrAADistanceFieldPathRenderer::PathDataList PathDataList; | 563 typedef GrAADistanceFieldPathRenderer::ShapeDataList ShapeDataList; |
| 583 PathTestStruct() : fContextID(SK_InvalidGenID), fAtlas(nullptr) {} | 564 PathTestStruct() : fContextID(SK_InvalidGenID), fAtlas(nullptr) {} |
| 584 ~PathTestStruct() { this->reset(); } | 565 ~PathTestStruct() { this->reset(); } |
| 585 | 566 |
| 586 void reset() { | 567 void reset() { |
| 587 PathDataList::Iter iter; | 568 ShapeDataList::Iter iter; |
| 588 iter.init(fPathList, PathDataList::Iter::kHead_IterStart); | 569 iter.init(fShapeList, ShapeDataList::Iter::kHead_IterStart); |
| 589 PathData* pathData; | 570 ShapeData* shapeData; |
| 590 while ((pathData = iter.get())) { | 571 while ((shapeData = iter.get())) { |
| 591 iter.next(); | 572 iter.next(); |
| 592 fPathList.remove(pathData); | 573 fShapeList.remove(shapeData); |
| 593 delete pathData; | 574 delete shapeData; |
| 594 } | 575 } |
| 595 delete fAtlas; | 576 delete fAtlas; |
| 596 fPathCache.reset(); | 577 fShapeCache.reset(); |
| 597 } | 578 } |
| 598 | 579 |
| 599 static void HandleEviction(GrBatchAtlas::AtlasID id, void* pr) { | 580 static void HandleEviction(GrBatchAtlas::AtlasID id, void* pr) { |
| 600 PathTestStruct* dfpr = (PathTestStruct*)pr; | 581 PathTestStruct* dfpr = (PathTestStruct*)pr; |
| 601 // remove any paths that use this plot | 582 // remove any paths that use this plot |
| 602 PathDataList::Iter iter; | 583 ShapeDataList::Iter iter; |
| 603 iter.init(dfpr->fPathList, PathDataList::Iter::kHead_IterStart); | 584 iter.init(dfpr->fShapeList, ShapeDataList::Iter::kHead_IterStart); |
| 604 PathData* pathData; | 585 ShapeData* shapeData; |
| 605 while ((pathData = iter.get())) { | 586 while ((shapeData = iter.get())) { |
| 606 iter.next(); | 587 iter.next(); |
| 607 if (id == pathData->fID) { | 588 if (id == shapeData->fID) { |
| 608 dfpr->fPathCache.remove(pathData->fKey); | 589 dfpr->fShapeCache.remove(shapeData->fKey); |
| 609 dfpr->fPathList.remove(pathData); | 590 dfpr->fShapeList.remove(shapeData); |
| 610 delete pathData; | 591 delete shapeData; |
| 611 } | 592 } |
| 612 } | 593 } |
| 613 } | 594 } |
| 614 | 595 |
| 615 uint32_t fContextID; | 596 uint32_t fContextID; |
| 616 GrBatchAtlas* fAtlas; | 597 GrBatchAtlas* fAtlas; |
| 617 PathCache fPathCache; | 598 ShapeCache fShapeCache; |
| 618 PathDataList fPathList; | 599 ShapeDataList fShapeList; |
| 619 }; | 600 }; |
| 620 | 601 |
| 621 DRAW_BATCH_TEST_DEFINE(AADistanceFieldPathBatch) { | 602 DRAW_BATCH_TEST_DEFINE(AADistanceFieldPathBatch) { |
| 622 static PathTestStruct gTestStruct; | 603 static PathTestStruct gTestStruct; |
| 623 | 604 |
| 624 if (context->uniqueID() != gTestStruct.fContextID) { | 605 if (context->uniqueID() != gTestStruct.fContextID) { |
| 625 gTestStruct.fContextID = context->uniqueID(); | 606 gTestStruct.fContextID = context->uniqueID(); |
| 626 gTestStruct.reset(); | 607 gTestStruct.reset(); |
| 627 gTestStruct.fAtlas = | 608 gTestStruct.fAtlas = |
| 628 context->resourceProvider()->createAtlas(kAlpha_8_GrPixelConfig, | 609 context->resourceProvider()->createAtlas(kAlpha_8_GrPixelConfig, |
| 629 ATLAS_TEXTURE_WIDTH, ATLAS_ TEXTURE_HEIGHT, | 610 ATLAS_TEXTURE_WIDTH, ATLAS_ TEXTURE_HEIGHT, |
| 630 NUM_PLOTS_X, NUM_PLOTS_Y, | 611 NUM_PLOTS_X, NUM_PLOTS_Y, |
| 631 &PathTestStruct::HandleEvic tion, | 612 &PathTestStruct::HandleEvic tion, |
| 632 (void*)&gTestStruct); | 613 (void*)&gTestStruct); |
| 633 } | 614 } |
| 634 | 615 |
| 635 SkMatrix viewMatrix = GrTest::TestMatrix(random); | 616 SkMatrix viewMatrix = GrTest::TestMatrix(random); |
| 636 GrColor color = GrRandomColor(random); | 617 GrColor color = GrRandomColor(random); |
| 637 bool gammaCorrect = random->nextBool(); | 618 bool gammaCorrect = random->nextBool(); |
| 638 | 619 |
| 639 AADistanceFieldPathBatch::Geometry geometry(GrTest::TestStrokeRec(random)); | 620 AADistanceFieldPathBatch::Geometry geometry; |
| 621 SkStrokeRec strokeRec = GrTest::TestStrokeRec(random); | |
| 622 GrShape shape(GrTest::TestPath(random), GrStyle(strokeRec, nullptr)); | |
| 623 geometry.fShape = shape; | |
| 640 geometry.fColor = color; | 624 geometry.fColor = color; |
| 641 geometry.fPath = GrTest::TestPath(random); | |
| 642 geometry.fAntiAlias = random->nextBool(); | 625 geometry.fAntiAlias = random->nextBool(); |
| 643 geometry.fGenID = random->nextU(); | |
| 644 | 626 |
| 645 return AADistanceFieldPathBatch::Create(geometry, viewMatrix, | 627 return AADistanceFieldPathBatch::Create(geometry, viewMatrix, |
| 646 gTestStruct.fAtlas, | 628 gTestStruct.fAtlas, |
| 647 &gTestStruct.fPathCache, | 629 &gTestStruct.fShapeCache, |
| 648 &gTestStruct.fPathList, | 630 &gTestStruct.fShapeList, |
| 649 gammaCorrect); | 631 gammaCorrect); |
| 650 } | 632 } |
| 651 | 633 |
| 652 #endif | 634 #endif |
| OLD | NEW |