Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(148)

Side by Side Diff: src/gpu/GrAADistanceFieldPathRenderer.cpp

Issue 975303005: Creation of GrBatchAtlas and Distancefieldpathrenderer batch (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: more tidying Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 1
2 /* 2 /*
3 * Copyright 2014 Google Inc. 3 * Copyright 2014 Google Inc.
4 * 4 *
5 * Use of this source code is governed by a BSD-style license that can be 5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file. 6 * found in the LICENSE file.
7 */ 7 */
8 8
9 #include "GrAADistanceFieldPathRenderer.h" 9 #include "GrAADistanceFieldPathRenderer.h"
10 10
11 #include "GrAtlas.h" 11 #include "GrBatch.h"
12 #include "GrBatchTarget.h"
13 #include "GrBufferAllocPool.h"
12 #include "GrContext.h" 14 #include "GrContext.h"
13 #include "GrPipelineBuilder.h" 15 #include "GrPipelineBuilder.h"
14 #include "GrSurfacePriv.h" 16 #include "GrSurfacePriv.h"
15 #include "GrSWMaskHelper.h" 17 #include "GrSWMaskHelper.h"
16 #include "GrTexturePriv.h" 18 #include "GrTexturePriv.h"
17 #include "effects/GrDistanceFieldTextureEffect.h" 19 #include "effects/GrDistanceFieldTextureEffect.h"
18 20
19 #include "SkDistanceFieldGen.h" 21 #include "SkDistanceFieldGen.h"
20 #include "SkRTConf.h" 22 #include "SkRTConf.h"
21 23
22 #define ATLAS_TEXTURE_WIDTH 1024 24 #define ATLAS_TEXTURE_WIDTH 1024
23 #define ATLAS_TEXTURE_HEIGHT 2048 25 #define ATLAS_TEXTURE_HEIGHT 2048
24 #define PLOT_WIDTH 256 26 #define PLOT_WIDTH 256
25 #define PLOT_HEIGHT 256 27 #define PLOT_HEIGHT 256
26 28
27 #define NUM_PLOTS_X (ATLAS_TEXTURE_WIDTH / PLOT_WIDTH) 29 #define NUM_PLOTS_X (ATLAS_TEXTURE_WIDTH / PLOT_WIDTH)
28 #define NUM_PLOTS_Y (ATLAS_TEXTURE_HEIGHT / PLOT_HEIGHT) 30 #define NUM_PLOTS_Y (ATLAS_TEXTURE_HEIGHT / PLOT_HEIGHT)
29 31
30 SK_CONF_DECLARE(bool, c_DumpPathCache, "gpu.dumpPathCache", false,
31 "Dump the contents of the path cache before every purge.");
32
33 #ifdef DF_PATH_TRACKING 32 #ifdef DF_PATH_TRACKING
34 static int g_NumCachedPaths = 0; 33 static int g_NumCachedPaths = 0;
35 static int g_NumFreedPaths = 0; 34 static int g_NumFreedPaths = 0;
36 #endif 35 #endif
37 36
38 // mip levels 37 // mip levels
39 static const int kSmallMIP = 32; 38 static const int kSmallMIP = 32;
40 static const int kMediumMIP = 78; 39 static const int kMediumMIP = 78;
41 static const int kLargeMIP = 192; 40 static const int kLargeMIP = 192;
42 41
43 //////////////////////////////////////////////////////////////////////////////// 42 ////////////////////////////////////////////////////////////////////////////////
44 GrAADistanceFieldPathRenderer::GrAADistanceFieldPathRenderer(GrContext* context) 43 GrAADistanceFieldPathRenderer::GrAADistanceFieldPathRenderer(GrContext* context)
45 : fContext(context) 44 : fContext(context)
46 , fAtlas(NULL) 45 , fAtlas(NULL) {
47 , fEffectFlags(kInvalid_DistanceFieldEffectFlag) {
48 } 46 }
49 47
50 GrAADistanceFieldPathRenderer::~GrAADistanceFieldPathRenderer() { 48 GrAADistanceFieldPathRenderer::~GrAADistanceFieldPathRenderer() {
51 PathDataList::Iter iter; 49 PathDataList::Iter iter;
52 iter.init(fPathList, PathDataList::Iter::kHead_IterStart); 50 iter.init(fPathList, PathDataList::Iter::kHead_IterStart);
53 PathData* pathData; 51 PathData* pathData;
54 while ((pathData = iter.get())) { 52 while ((pathData = iter.get())) {
55 iter.next(); 53 iter.next();
56 fPathList.remove(pathData); 54 fPathList.remove(pathData);
57 SkDELETE(pathData); 55 SkDELETE(pathData);
58 } 56 }
59 57
60 SkDELETE(fAtlas); 58 if (fAtlas) {
bsalomon 2015/03/05 22:11:08 delete is legal on NULL.
joshualitt 2015/03/09 19:45:14 Acknowledged.
59 SkDELETE(fAtlas);
60 }
61 61
62 #ifdef DF_PATH_TRACKING 62 #ifdef DF_PATH_TRACKING
63 SkDebugf("Cached paths: %d, freed paths: %d\n", g_NumCachedPaths, g_NumFreed Paths); 63 SkDebugf("Cached paths: %d, freed paths: %d\n", g_NumCachedPaths, g_NumFreed Paths);
64 #endif 64 #endif
65 } 65 }
66 66
67 //////////////////////////////////////////////////////////////////////////////// 67 ////////////////////////////////////////////////////////////////////////////////
68 bool GrAADistanceFieldPathRenderer::canDrawPath(const GrDrawTarget* target, 68 bool GrAADistanceFieldPathRenderer::canDrawPath(const GrDrawTarget* target,
69 const GrPipelineBuilder* pipelin eBuilder, 69 const GrPipelineBuilder* pipelin eBuilder,
70 const SkMatrix& viewMatrix, 70 const SkMatrix& viewMatrix,
(...skipping 25 matching lines...) Expand all
96 GrPathRenderer::StencilSupport 96 GrPathRenderer::StencilSupport
97 GrAADistanceFieldPathRenderer::onGetStencilSupport(const GrDrawTarget*, 97 GrAADistanceFieldPathRenderer::onGetStencilSupport(const GrDrawTarget*,
98 const GrPipelineBuilder*, 98 const GrPipelineBuilder*,
99 const SkPath&, 99 const SkPath&,
100 const SkStrokeRec&) const { 100 const SkStrokeRec&) const {
101 return GrPathRenderer::kNoSupport_StencilSupport; 101 return GrPathRenderer::kNoSupport_StencilSupport;
102 } 102 }
103 103
104 //////////////////////////////////////////////////////////////////////////////// 104 ////////////////////////////////////////////////////////////////////////////////
105 105
106
107 class AADistanceFieldPathBatch : public GrBatch {
108 public:
109 typedef GrAADistanceFieldPathRenderer::PathData PathData;
110 typedef SkTDynamicHash<PathData, PathData::Key> PathCache;
111 typedef GrAADistanceFieldPathRenderer::PathDataList PathDataList;
112
113 struct Geometry {
114 Geometry(const SkStrokeRec& stroke) : fStroke(stroke) {}
115 SkPath fPath;
116 SkStrokeRec fStroke;
117 bool fAntiAlias;
118 PathData* fPathData;
119 };
120
121 static GrBatch* Create(const Geometry& geometry, GrColor color, const SkMatr ix& viewMatrix,
122 GrBatchAtlas* atlas, PathCache* pathCache, PathDataLi st* pathList) {
123 return SkNEW_ARGS(AADistanceFieldPathBatch, (geometry, color, viewMatrix ,
124 atlas, pathCache, pathList) );
125 }
126
127 const char* name() const SK_OVERRIDE { return "AADistanceFieldPathBatch"; }
128
129 void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE {
130 out->setKnownFourComponents(fBatch.fColor);
131 }
132
133 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRID E {
134 out->setUnknownSingleComponent();
135 }
136
137 void initBatchTracker(const GrPipelineInfo& init) SK_OVERRIDE {
138 // Handle any color overrides
139 if (init.fColorIgnored) {
140 fBatch.fColor = GrColor_ILLEGAL;
141 } else if (GrColor_ILLEGAL != init.fOverrideColor) {
142 fBatch.fColor = init.fOverrideColor;
143 }
144
145 // setup batch properties
146 fBatch.fColorIgnored = init.fColorIgnored;
147 fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
148 fBatch.fCoverageIgnored = init.fCoverageIgnored;
149 }
150
151 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline ) SK_OVERRIDE {
152 int instanceCount = fGeoData.count();
153
154 SkMatrix invert;
155 if (this->usesLocalCoords() && !this->viewMatrix().invert(&invert)) {
156 SkDebugf("Could not invert viewmatrix\n");
157 return;
158 }
159
160 uint32_t flags = 0;
161 flags |= this->viewMatrix().isSimilarity() ? kSimilarity_DistanceFieldEf fectFlag : 0;
162
163 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBil erp_FilterMode);
164
165 // Setup GrGeometryProcessor
166 GrBatchAtlas* atlas = fAtlas;
167 SkAutoTUnref<GrGeometryProcessor> dfProcessor(
168 GrDistanceFieldNoGammaTextureEffect::Create(this->color(),
169 this->viewMatrix(),
170 atlas->getTexture(),
171 params,
172 flags,
173 false));
174
175 this->initDraw(batchTarget, dfProcessor, pipeline);
176
177 // allocate vertices
178 size_t vertexStride = dfProcessor->getVertexStride();
179 SkASSERT(vertexStride == 2 * sizeof(SkPoint));
180
181 int vertexCount = GrBatchTarget::kVertsPerRect * instanceCount;
182
183 const GrVertexBuffer* vertexBuffer;
184 int firstVertex;
185
186 void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
187 vertexCount,
188 &vertexBuffer,
189 &firstVertex);
190
191 // We may have to flush while uploading path data to the atlas, so we se t up the draw here
192 const GrIndexBuffer* quadIndexBuffer = batchTarget->quadIndexBuffer();
193 int maxInstancesPerDraw = quadIndexBuffer->maxQuads();
194
195 GrDrawTarget::DrawInfo drawInfo;
196 drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
197 drawInfo.setStartVertex(0);
198 drawInfo.setStartIndex(0);
199 drawInfo.setVerticesPerInstance(GrBatchTarget::kVertsPerRect);
200 drawInfo.setIndicesPerInstance(GrBatchTarget::kIndicesPerRect);
201 drawInfo.adjustStartVertex(firstVertex);
202 drawInfo.setVertexBuffer(vertexBuffer);
203 drawInfo.setIndexBuffer(quadIndexBuffer);
204
205 int instancesToFlush = 0;
206 for (int i = 0; i < instanceCount; i++) {
207 Geometry& args = fGeoData[i];
208
209 // get mip level
210 SkScalar maxScale = this->viewMatrix().getMaxScale();
211 const SkRect& bounds = args.fPath.getBounds();
212 SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height());
213 SkScalar size = maxScale * maxDim;
214 uint32_t desiredDimension;
215 if (size <= kSmallMIP) {
216 desiredDimension = kSmallMIP;
217 } else if (size <= kMediumMIP) {
218 desiredDimension = kMediumMIP;
219 } else {
220 desiredDimension = kLargeMIP;
221 }
222
223 // check to see if path is cached
224 // TODO: handle stroked vs. filled version of same path
225 PathData::Key key = { args.fPath.getGenerationID(), desiredDimension };
226 args.fPathData = fPathCache->find(key);
227 if (NULL == args.fPathData || !atlas->hasID(args.fPathData->fID)) {
228 // Remove the stale cache entry
229 if (args.fPathData) {
230 fPathCache->remove(args.fPathData->fKey);
231 fPathList->remove(args.fPathData);
232 SkDELETE(args.fPathData);
233 }
234 SkScalar scale = desiredDimension/maxDim;
235 args.fPathData = SkNEW(PathData);
236 if (!this->addPathToAtlas(batchTarget,
237 dfProcessor,
238 pipeline,
239 &drawInfo,
240 &instancesToFlush,
241 maxInstancesPerDraw,
242 atlas,
243 args.fPathData,
244 args.fPath,
245 args.fStroke,
246 args.fAntiAlias,
247 desiredDimension,
248 scale)) {
249 SkDebugf("Can't rasterize path\n");
250 return;
251 }
252 }
253
254 atlas->setLastRefToken(args.fPathData->fID, batchTarget->currentToke n());
255
256 // Now set vertices
257 intptr_t offset = reinterpret_cast<intptr_t>(vertices);
258 offset += i * GrBatchTarget::kVertsPerRect * vertexStride;
259 SkPoint* positions = reinterpret_cast<SkPoint*>(offset);
260 this->drawPath(batchTarget,
261 atlas,
262 pipeline,
263 dfProcessor,
264 positions,
265 vertexStride,
266 this->viewMatrix(),
267 args.fPath,
268 args.fPathData);
269 instancesToFlush++;
270 }
271
272 this->flush(batchTarget, dfProcessor, pipeline, &drawInfo, instancesToFl ush,
273 maxInstancesPerDraw);
274 }
275
276 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
277
278 private:
279 AADistanceFieldPathBatch(const Geometry& geometry, GrColor color, const SkMa trix& viewMatrix,
280 GrBatchAtlas* atlas,
281 PathCache* pathCache, PathDataList* pathList) {
282 this->initClassID<AADistanceFieldPathBatch>();
283 fBatch.fColor = color;
284 fBatch.fViewMatrix = viewMatrix;
285 fGeoData.push_back(geometry);
286 fGeoData.back().fPathData = NULL;
287
288 fAtlas = atlas;
289 fPathCache = pathCache;
290 fPathList = pathList;
291 }
292
293 bool addPathToAtlas(GrBatchTarget* batchTarget,
294 const GrGeometryProcessor* dfProcessor,
295 const GrPipeline* pipeline,
296 GrDrawTarget::DrawInfo* drawInfo,
297 int* instancesToFlush,
298 int maxInstancesPerDraw,
299 GrBatchAtlas* atlas,
300 PathData* pathData,
301 const SkPath& path,
302 const SkStrokeRec&
303 stroke, bool antiAlias,
304 uint32_t dimension,
305 SkScalar scale) {
306 const SkRect& bounds = path.getBounds();
307
308 // generate bounding rect for bitmap draw
309 SkRect scaledBounds = bounds;
310 // scale to mip level size
311 scaledBounds.fLeft *= scale;
312 scaledBounds.fTop *= scale;
313 scaledBounds.fRight *= scale;
314 scaledBounds.fBottom *= scale;
315 // move the origin to an integer boundary (gives better results)
316 SkScalar dx = SkScalarFraction(scaledBounds.fLeft);
317 SkScalar dy = SkScalarFraction(scaledBounds.fTop);
318 scaledBounds.offset(-dx, -dy);
319 // get integer boundary
320 SkIRect devPathBounds;
321 scaledBounds.roundOut(&devPathBounds);
322 // pad to allow room for antialiasing
323 devPathBounds.outset(SkScalarCeilToInt(kAntiAliasPad), SkScalarCeilToInt (kAntiAliasPad));
324 // move origin to upper left corner
325 devPathBounds.offsetTo(0,0);
326
327 // draw path to bitmap
328 SkMatrix drawMatrix;
329 drawMatrix.setTranslate(-bounds.left(), -bounds.top());
330 drawMatrix.postScale(scale, scale);
331 drawMatrix.postTranslate(kAntiAliasPad, kAntiAliasPad);
332
333 // setup bitmap backing
334 // Now translate so the bound's UL corner is at the origin
335 drawMatrix.postTranslate(-devPathBounds.fLeft * SK_Scalar1,
336 -devPathBounds.fTop * SK_Scalar1);
337 SkIRect pathBounds = SkIRect::MakeWH(devPathBounds.width(),
338 devPathBounds.height());
339
340 SkBitmap bmp;
341 const SkImageInfo bmImageInfo = SkImageInfo::MakeA8(pathBounds.fRight,
342 pathBounds.fBottom);
343 if (!bmp.tryAllocPixels(bmImageInfo)) {
344 return false;
345 }
346
347 sk_bzero(bmp.getPixels(), bmp.getSafeSize());
348
349 // rasterize path
350 SkPaint paint;
351 if (stroke.isHairlineStyle()) {
352 paint.setStyle(SkPaint::kStroke_Style);
353 paint.setStrokeWidth(SK_Scalar1);
354 } else {
355 if (stroke.isFillStyle()) {
356 paint.setStyle(SkPaint::kFill_Style);
357 } else {
358 paint.setStyle(SkPaint::kStroke_Style);
359 paint.setStrokeJoin(stroke.getJoin());
360 paint.setStrokeCap(stroke.getCap());
361 paint.setStrokeWidth(stroke.getWidth());
362 }
363 }
364 paint.setAntiAlias(antiAlias);
365
366 SkDraw draw;
367 sk_bzero(&draw, sizeof(draw));
368
369 SkRasterClip rasterClip;
370 rasterClip.setRect(pathBounds);
371 draw.fRC = &rasterClip;
372 draw.fClip = &rasterClip.bwRgn();
373 draw.fMatrix = &drawMatrix;
374 draw.fBitmap = &bmp;
375
376 draw.drawPathCoverage(path, paint);
377
378 // generate signed distance field
379 devPathBounds.outset(SK_DistanceFieldPad, SK_DistanceFieldPad);
380 int width = devPathBounds.width();
381 int height = devPathBounds.height();
382 // TODO We should really generate this directly into the plot somehow
383 SkAutoSMalloc<1024> dfStorage(width * height * sizeof(unsigned char));
384
385 // Generate signed distance field
386 {
387 SkAutoLockPixels alp(bmp);
388
389 SkGenerateDistanceFieldFromA8Image((unsigned char*)dfStorage.get(),
390 (const unsigned char*)bmp.getPixe ls(),
391 bmp.width(), bmp.height(), bmp.ro wBytes());
392 }
393
394 // add to atlas
395 SkIPoint16 atlasLocation;
396 GrBatchAtlas::AtlasID id;
397 bool success = atlas->addToAtlas(&id, batchTarget, width, height, dfStor age.get(),
398 &atlasLocation);
399 if (!success) {
400 this->flush(batchTarget, dfProcessor, pipeline, drawInfo, *instances ToFlush,
401 maxInstancesPerDraw);
402 this->initDraw(batchTarget, dfProcessor, pipeline);
403 *instancesToFlush = 0;
404
405 SkDEBUGCODE(success =) atlas->addToAtlas(&id, batchTarget, width, he ight,
406 dfStorage.get(), &atlasLoca tion);
407 SkASSERT(success);
408
409 }
410
411 // add to cache
412 pathData->fKey.fGenID = path.getGenerationID();
413 pathData->fKey.fDimension = dimension;
414 pathData->fScale = scale;
415 pathData->fID = id;
416 // change the scaled rect to match the size of the inset distance field
417 scaledBounds.fRight = scaledBounds.fLeft +
418 SkIntToScalar(devPathBounds.width() - 2*SK_DistanceFieldInset);
419 scaledBounds.fBottom = scaledBounds.fTop +
420 SkIntToScalar(devPathBounds.height() - 2*SK_DistanceFieldInset);
421 // shift the origin to the correct place relative to the distance field
422 // need to also restore the fractional translation
423 scaledBounds.offset(-SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPa d + dx,
424 -SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPa d + dy);
425 pathData->fBounds = scaledBounds;
426 // origin we render from is inset from distance field edge
427 atlasLocation.fX += SK_DistanceFieldInset;
428 atlasLocation.fY += SK_DistanceFieldInset;
429 pathData->fAtlasLocation = atlasLocation;
430
431 fPathCache->add(pathData);
432 fPathList->addToTail(pathData);
433 #ifdef DF_PATH_TRACKING
434 ++g_NumCachedPaths;
435 #endif
436 return true;
437 }
438
439 void drawPath(GrBatchTarget* target,
440 GrBatchAtlas* atlas,
441 const GrPipeline* pipeline,
442 const GrGeometryProcessor* gp,
443 SkPoint* positions,
444 size_t vertexStride,
445 const SkMatrix& viewMatrix,
446 const SkPath& path,
447 const PathData* pathData) {
448 GrTexture* texture = atlas->getTexture();
449
450 SkScalar dx = pathData->fBounds.fLeft;
451 SkScalar dy = pathData->fBounds.fTop;
452 SkScalar width = pathData->fBounds.width();
453 SkScalar height = pathData->fBounds.height();
454
455 SkScalar invScale = 1.0f / pathData->fScale;
456 dx *= invScale;
457 dy *= invScale;
458 width *= invScale;
459 height *= invScale;
460
461 SkFixed tx = SkIntToFixed(pathData->fAtlasLocation.fX);
462 SkFixed ty = SkIntToFixed(pathData->fAtlasLocation.fY);
463 SkFixed tw = SkScalarToFixed(pathData->fBounds.width());
464 SkFixed th = SkScalarToFixed(pathData->fBounds.height());
465
466 // vertex positions
467 // TODO make the vertex attributes a struct
468 SkRect r = SkRect::MakeXYWH(dx, dy, width, height);
469 positions->setRectFan(r.left(), r.top(), r.right(), r.bottom(), vertexSt ride);
470
471 // vertex texture coords
472 SkPoint* textureCoords = positions + 1;
473 textureCoords->setRectFan(SkFixedToFloat(texture->texturePriv().normaliz eFixedX(tx)),
474 SkFixedToFloat(texture->texturePriv().normaliz eFixedY(ty)),
475 SkFixedToFloat(texture->texturePriv().normaliz eFixedX(tx + tw)),
476 SkFixedToFloat(texture->texturePriv().normaliz eFixedY(ty + th)),
477 vertexStride);
478 }
479
480 void initDraw(GrBatchTarget* batchTarget,
481 const GrGeometryProcessor* dfProcessor,
482 const GrPipeline* pipeline) {
483 batchTarget->initDraw(dfProcessor, pipeline);
484
485 // TODO remove this when batch is everywhere
486 GrPipelineInfo init;
487 init.fColorIgnored = fBatch.fColorIgnored;
488 init.fOverrideColor = GrColor_ILLEGAL;
489 init.fCoverageIgnored = fBatch.fCoverageIgnored;
490 init.fUsesLocalCoords = this->usesLocalCoords();
491 dfProcessor->initBatchTracker(batchTarget->currentBatchTracker(), init);
492 }
493
494 void flush(GrBatchTarget* batchTarget,
495 const GrGeometryProcessor* dfProcessor,
496 const GrPipeline* pipeline,
497 GrDrawTarget::DrawInfo* drawInfo,
498 int instanceCount,
499 int maxInstancesPerDraw) {
500 while (instanceCount) {
501 drawInfo->setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw ));
502 drawInfo->setVertexCount(drawInfo->instanceCount() * drawInfo->verti cesPerInstance());
503 drawInfo->setIndexCount(drawInfo->instanceCount() * drawInfo->indice sPerInstance());
504
505 batchTarget->draw(*drawInfo);
506
507 drawInfo->setStartVertex(drawInfo->startVertex() + drawInfo->vertexC ount());
508 instanceCount -= drawInfo->instanceCount();
509 }
510 }
511
512 GrColor color() const { return fBatch.fColor; }
513 const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; }
514 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
515
516 bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE {
517 AADistanceFieldPathBatch* that = t->cast<AADistanceFieldPathBatch>();
518
519 // TODO we could actually probably do a bunch of this work on the CPU, i e map viewMatrix,
520 // maybe upload color via attribute
521 if (this->color() != that->color()) {
522 return false;
523 }
524
525 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
526 return false;
527 }
528
529 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin()) ;
bsalomon 2015/03/05 22:11:08 seems like this could lead to unfortunate combinat
bsalomon 2015/03/06 16:34:59 Retracted... realized this doesn't lead to caching
530 return true;
531 }
532
533 struct BatchTracker {
534 GrColor fColor;
535 SkMatrix fViewMatrix;
536 bool fUsesLocalCoords;
537 bool fColorIgnored;
538 bool fCoverageIgnored;
539 };
540
541 BatchTracker fBatch;
542 SkSTArray<1, Geometry, true> fGeoData;
543
544 // padding around path bounds to allow for antialiased pixels
545 const SkScalar kAntiAliasPad = 1.0f;
bsalomon 2015/03/05 22:11:08 does this require c++11? (do we allow anything els
joshualitt 2015/03/09 19:45:14 Acknowledged.
546 GrBatchAtlas* fAtlas;
547 PathCache* fPathCache;
548 PathDataList* fPathList;
549 };
550
106 bool GrAADistanceFieldPathRenderer::onDrawPath(GrDrawTarget* target, 551 bool GrAADistanceFieldPathRenderer::onDrawPath(GrDrawTarget* target,
107 GrPipelineBuilder* pipelineBuilde r, 552 GrPipelineBuilder* pipelineBuilde r,
108 GrColor color, 553 GrColor color,
109 const SkMatrix& viewMatrix, 554 const SkMatrix& viewMatrix,
110 const SkPath& path, 555 const SkPath& path,
111 const SkStrokeRec& stroke, 556 const SkStrokeRec& stroke,
112 bool antiAlias) { 557 bool antiAlias) {
113 // we've already bailed on inverse filled paths, so this is safe 558 // we've already bailed on inverse filled paths, so this is safe
114 if (path.isEmpty()) { 559 if (path.isEmpty()) {
115 return true; 560 return true;
116 } 561 }
117 562
118 SkASSERT(fContext); 563 SkASSERT(fContext);
119 564
120 // get mip level 565 if (!fAtlas) {
121 SkScalar maxScale = viewMatrix.getMaxScale(); 566 // Create a new atlas
122 const SkRect& bounds = path.getBounds(); 567 GrSurfaceDesc desc;
123 SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height()); 568 desc.fFlags = kNone_GrSurfaceFlags;
124 SkScalar size = maxScale*maxDim; 569 desc.fWidth = ATLAS_TEXTURE_WIDTH;
125 uint32_t desiredDimension; 570 desc.fHeight = ATLAS_TEXTURE_HEIGHT;
126 if (size <= kSmallMIP) { 571 desc.fConfig = kAlpha_8_GrPixelConfig;
127 desiredDimension = kSmallMIP; 572
128 } else if (size <= kMediumMIP) { 573 GrGpu* gpu = fContext->getGpu();
129 desiredDimension = kMediumMIP; 574 GrTexture* texture = gpu->createTexture(desc, true, NULL, 0);
bsalomon 2015/03/05 22:11:08 not using the cache?
joshualitt 2015/03/09 19:45:14 Acknowledged.
130 } else { 575 if (texture) {
131 desiredDimension = kLargeMIP; 576 fAtlas = SkNEW_ARGS(GrBatchAtlas, (gpu, texture, NUM_PLOTS_X, NUM_PL OTS_Y));
132 } 577 }
133 578 }
134 // check to see if path is cached 579
135 // TODO: handle stroked vs. filled version of same path 580 AADistanceFieldPathBatch::Geometry geometry(stroke);
136 PathData::Key key = { path.getGenerationID(), desiredDimension }; 581 geometry.fPath = path;
137 PathData* pathData = fPathCache.find(key); 582 geometry.fAntiAlias = antiAlias;
138 if (NULL == pathData) { 583
139 SkScalar scale = desiredDimension/maxDim; 584 SkAutoTUnref<GrBatch> batch(AADistanceFieldPathBatch::Create(geometry, color , viewMatrix,
140 pathData = this->addPathToAtlas(path, stroke, antiAlias, desiredDimensio n, scale); 585 fAtlas, &fPathC ache, &fPathList));
141 if (NULL == pathData) { 586
142 return false; 587 SkRect bounds = path.getBounds();
143 } 588 viewMatrix.mapRect(&bounds);
144 } 589 target->drawBatch(pipelineBuilder, batch, &bounds);
145 590
146 // use signed distance field to render
147 return this->internalDrawPath(target, pipelineBuilder, color, viewMatrix, pa th, pathData);
148 }
149
150 // padding around path bounds to allow for antialiased pixels
151 const SkScalar kAntiAliasPad = 1.0f;
152
153 inline bool GrAADistanceFieldPathRenderer::uploadPath(GrPlot** plot, SkIPoint16* atlasLocation,
154 int width, int height, voi d* dfStorage) {
155 *plot = fAtlas->addToAtlas(&fPlotUsage, width, height, dfStorage, atlasLocat ion);
156
157 // if atlas full
158 if (NULL == *plot) {
159 if (this->freeUnusedPlot()) {
160 *plot = fAtlas->addToAtlas(&fPlotUsage, width, height, dfStorage, at lasLocation);
161 if (*plot) {
162 return true;
163 }
164 }
165
166 if (c_DumpPathCache) {
167 #ifdef SK_DEVELOPER
168 GrTexture* texture = fAtlas->getTexture();
169 texture->surfacePriv().savePixels("pathcache.png");
170 #endif
171 }
172
173 // before we purge the cache, we must flush any accumulated draws
174 fContext->flush();
175
176 if (this->freeUnusedPlot()) {
177 *plot = fAtlas->addToAtlas(&fPlotUsage, width, height, dfStorage, at lasLocation);
178 if (*plot) {
179 return true;
180 }
181 }
182 return false;
183 }
184 return true; 591 return true;
185 } 592 }
186 593
187 GrAADistanceFieldPathRenderer::PathData* GrAADistanceFieldPathRenderer::addPathT oAtlas(
188 const Sk Path& path,
189 const Sk StrokeRec& stroke,
190 bool ant iAlias,
191 uint32_t dimension,
192 SkScalar scale) {
193
194 // generate distance field and add to atlas
195 if (NULL == fAtlas) {
196 SkISize textureSize = SkISize::Make(ATLAS_TEXTURE_WIDTH, ATLAS_TEXTURE_H EIGHT);
197 fAtlas = SkNEW_ARGS(GrAtlas, (fContext->getGpu(), kAlpha_8_GrPixelConfig ,
198 kNone_GrSurfaceFlags, textureSize,
199 NUM_PLOTS_X, NUM_PLOTS_Y, false));
200 if (NULL == fAtlas) {
201 return NULL;
202 }
203 }
204
205 const SkRect& bounds = path.getBounds();
206
207 // generate bounding rect for bitmap draw
208 SkRect scaledBounds = bounds;
209 // scale to mip level size
210 scaledBounds.fLeft *= scale;
211 scaledBounds.fTop *= scale;
212 scaledBounds.fRight *= scale;
213 scaledBounds.fBottom *= scale;
214 // move the origin to an integer boundary (gives better results)
215 SkScalar dx = SkScalarFraction(scaledBounds.fLeft);
216 SkScalar dy = SkScalarFraction(scaledBounds.fTop);
217 scaledBounds.offset(-dx, -dy);
218 // get integer boundary
219 SkIRect devPathBounds;
220 scaledBounds.roundOut(&devPathBounds);
221 // pad to allow room for antialiasing
222 devPathBounds.outset(SkScalarCeilToInt(kAntiAliasPad), SkScalarCeilToInt(kAn tiAliasPad));
223 // move origin to upper left corner
224 devPathBounds.offsetTo(0,0);
225
226 // draw path to bitmap
227 SkMatrix drawMatrix;
228 drawMatrix.setTranslate(-bounds.left(), -bounds.top());
229 drawMatrix.postScale(scale, scale);
230 drawMatrix.postTranslate(kAntiAliasPad, kAntiAliasPad);
231 GrSWMaskHelper helper(fContext);
232
233 if (!helper.init(devPathBounds, &drawMatrix)) {
234 return NULL;
235 }
236 helper.draw(path, stroke, SkRegion::kReplace_Op, antiAlias, 0xFF);
237
238 // generate signed distance field
239 devPathBounds.outset(SK_DistanceFieldPad, SK_DistanceFieldPad);
240 int width = devPathBounds.width();
241 int height = devPathBounds.height();
242 SkAutoSMalloc<1024> dfStorage(width*height*sizeof(unsigned char));
243 helper.toSDF((unsigned char*) dfStorage.get());
244
245 // add to atlas
246 GrPlot* plot;
247 SkIPoint16 atlasLocation;
248 if (!this->uploadPath(&plot, &atlasLocation, width, height, dfStorage.get()) ) {
249 return NULL;
250 }
251
252 // add to cache
253 PathData* pathData = SkNEW(PathData);
254 pathData->fKey.fGenID = path.getGenerationID();
255 pathData->fKey.fDimension = dimension;
256 pathData->fScale = scale;
257 pathData->fPlot = plot;
258 // change the scaled rect to match the size of the inset distance field
259 scaledBounds.fRight = scaledBounds.fLeft +
260 SkIntToScalar(devPathBounds.width() - 2*SK_DistanceFieldInset);
261 scaledBounds.fBottom = scaledBounds.fTop +
262 SkIntToScalar(devPathBounds.height() - 2*SK_DistanceFieldInset);
263 // shift the origin to the correct place relative to the distance field
264 // need to also restore the fractional translation
265 scaledBounds.offset(-SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPad + dx,
266 -SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPad + dy);
267 pathData->fBounds = scaledBounds;
268 // origin we render from is inset from distance field edge
269 atlasLocation.fX += SK_DistanceFieldInset;
270 atlasLocation.fY += SK_DistanceFieldInset;
271 pathData->fAtlasLocation = atlasLocation;
272
273 fPathCache.add(pathData);
274 fPathList.addToTail(pathData);
275 #ifdef DF_PATH_TRACKING
276 ++g_NumCachedPaths;
277 #endif
278
279 return pathData;
280 }
281
282 bool GrAADistanceFieldPathRenderer::freeUnusedPlot() {
283 // find an unused plot
284 GrPlot* plot = fAtlas->getUnusedPlot();
285 if (NULL == plot) {
286 return false;
287 }
288 plot->resetRects();
289
290 // remove any paths that use this plot
291 PathDataList::Iter iter;
292 iter.init(fPathList, PathDataList::Iter::kHead_IterStart);
293 PathData* pathData;
294 while ((pathData = iter.get())) {
295 iter.next();
296 if (plot == pathData->fPlot) {
297 fPathCache.remove(pathData->fKey);
298 fPathList.remove(pathData);
299 SkDELETE(pathData);
300 #ifdef DF_PATH_TRACKING
301 ++g_NumFreedPaths;
302 #endif
303 }
304 }
305
306 // tell the atlas to free the plot
307 GrAtlas::RemovePlot(&fPlotUsage, plot);
308
309 return true;
310 }
311
312 bool GrAADistanceFieldPathRenderer::internalDrawPath(GrDrawTarget* target,
313 GrPipelineBuilder* pipeline Builder,
314 GrColor color,
315 const SkMatrix& viewMatrix,
316 const SkPath& path,
317 const PathData* pathData) {
318 GrTexture* texture = fAtlas->getTexture();
319 GrPipelineBuilder::AutoRestoreFragmentProcessors arfp(pipelineBuilder);
320
321 SkASSERT(pathData->fPlot);
322 GrDrawTarget::DrawToken drawToken = target->getCurrentDrawToken();
323 pathData->fPlot->setDrawToken(drawToken);
324
325 // set up any flags
326 uint32_t flags = 0;
327 flags |= viewMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0 ;
328
329 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_ FilterMode);
330 if (flags != fEffectFlags || fCachedGeometryProcessor->color() != color ||
331 !fCachedGeometryProcessor->viewMatrix().cheapEqualTo(viewMatrix)) {
332 fCachedGeometryProcessor.reset(GrDistanceFieldNoGammaTextureEffect::Crea te(color,
333 viewMatrix,
334 texture,
335 params,
336 flags,
337 false));
338 fEffectFlags = flags;
339 }
340
341 void* vertices = NULL;
342 bool success = target->reserveVertexAndIndexSpace(4,
343 fCachedGeometryProcessor-> getVertexStride(),
344 0, &vertices, NULL);
345 SkASSERT(fCachedGeometryProcessor->getVertexStride() == 2 * sizeof(SkPoint)) ;
346 GrAlwaysAssert(success);
347
348 SkScalar dx = pathData->fBounds.fLeft;
349 SkScalar dy = pathData->fBounds.fTop;
350 SkScalar width = pathData->fBounds.width();
351 SkScalar height = pathData->fBounds.height();
352
353 SkScalar invScale = 1.0f/pathData->fScale;
354 dx *= invScale;
355 dy *= invScale;
356 width *= invScale;
357 height *= invScale;
358
359 SkFixed tx = SkIntToFixed(pathData->fAtlasLocation.fX);
360 SkFixed ty = SkIntToFixed(pathData->fAtlasLocation.fY);
361 SkFixed tw = SkScalarToFixed(pathData->fBounds.width());
362 SkFixed th = SkScalarToFixed(pathData->fBounds.height());
363
364 // vertex positions
365 SkRect r = SkRect::MakeXYWH(dx, dy, width, height);
366 size_t vertSize = 2 * sizeof(SkPoint);
367 SkPoint* positions = reinterpret_cast<SkPoint*>(vertices);
368 positions->setRectFan(r.left(), r.top(), r.right(), r.bottom(), vertSize);
369
370 // vertex texture coords
371 intptr_t intPtr = reinterpret_cast<intptr_t>(positions);
372 SkPoint* textureCoords = reinterpret_cast<SkPoint*>(intPtr + vertSize - size of(SkPoint));
373 textureCoords->setRectFan(SkFixedToFloat(texture->texturePriv().normalizeFix edX(tx)),
374 SkFixedToFloat(texture->texturePriv().normalizeFix edY(ty)),
375 SkFixedToFloat(texture->texturePriv().normalizeFix edX(tx + tw)),
376 SkFixedToFloat(texture->texturePriv().normalizeFix edY(ty + th)),
377 vertSize);
378
379 viewMatrix.mapRect(&r);
380 target->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
381 target->drawIndexedInstances(pipelineBuilder, fCachedGeometryProcessor.get() ,
382 kTriangles_GrPrimitiveType, 1, 4, 6, &r);
383 target->resetVertexSource();
384
385 return true;
386 }
387
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698