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

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: nit 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
« no previous file with comments | « src/gpu/GrAADistanceFieldPathRenderer.h ('k') | src/gpu/GrBatch.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
42 // Callback to clear out internal path cache when eviction occurs
43 void GrAADistanceFieldPathRenderer::HandleEviction(GrBatchAtlas::AtlasID id, voi d* pr) {
44 GrAADistanceFieldPathRenderer* dfpr = (GrAADistanceFieldPathRenderer*)pr;
45 // remove any paths that use this plot
46 PathDataList::Iter iter;
47 iter.init(dfpr->fPathList, PathDataList::Iter::kHead_IterStart);
48 PathData* pathData;
49 while ((pathData = iter.get())) {
50 iter.next();
51 if (id == pathData->fID) {
52 dfpr->fPathCache.remove(pathData->fKey);
53 dfpr->fPathList.remove(pathData);
54 SkDELETE(pathData);
55 #ifdef DF_PATH_TRACKING
56 ++g_NumFreedPaths;
57 #endif
58 }
59 }
60 }
61
43 //////////////////////////////////////////////////////////////////////////////// 62 ////////////////////////////////////////////////////////////////////////////////
44 GrAADistanceFieldPathRenderer::GrAADistanceFieldPathRenderer(GrContext* context) 63 GrAADistanceFieldPathRenderer::GrAADistanceFieldPathRenderer(GrContext* context)
45 : fContext(context) 64 : fContext(context)
46 , fAtlas(NULL) 65 , fAtlas(NULL) {
47 , fEffectFlags(kInvalid_DistanceFieldEffectFlag) {
48 } 66 }
49 67
50 GrAADistanceFieldPathRenderer::~GrAADistanceFieldPathRenderer() { 68 GrAADistanceFieldPathRenderer::~GrAADistanceFieldPathRenderer() {
51 PathDataList::Iter iter; 69 PathDataList::Iter iter;
52 iter.init(fPathList, PathDataList::Iter::kHead_IterStart); 70 iter.init(fPathList, PathDataList::Iter::kHead_IterStart);
53 PathData* pathData; 71 PathData* pathData;
54 while ((pathData = iter.get())) { 72 while ((pathData = iter.get())) {
55 iter.next(); 73 iter.next();
56 fPathList.remove(pathData); 74 fPathList.remove(pathData);
57 SkDELETE(pathData); 75 SkDELETE(pathData);
58 } 76 }
59
60 SkDELETE(fAtlas); 77 SkDELETE(fAtlas);
61 78
62 #ifdef DF_PATH_TRACKING 79 #ifdef DF_PATH_TRACKING
63 SkDebugf("Cached paths: %d, freed paths: %d\n", g_NumCachedPaths, g_NumFreed Paths); 80 SkDebugf("Cached paths: %d, freed paths: %d\n", g_NumCachedPaths, g_NumFreed Paths);
64 #endif 81 #endif
65 } 82 }
66 83
67 //////////////////////////////////////////////////////////////////////////////// 84 ////////////////////////////////////////////////////////////////////////////////
68 bool GrAADistanceFieldPathRenderer::canDrawPath(const GrDrawTarget* target, 85 bool GrAADistanceFieldPathRenderer::canDrawPath(const GrDrawTarget* target,
69 const GrPipelineBuilder* pipelin eBuilder, 86 const GrPipelineBuilder* pipelin eBuilder,
(...skipping 12 matching lines...) Expand all
82 // currently don't support perspective 99 // currently don't support perspective
83 if (viewMatrix.hasPerspective()) { 100 if (viewMatrix.hasPerspective()) {
84 return false; 101 return false;
85 } 102 }
86 103
87 // only support paths smaller than 64x64, scaled to less than 256x256 104 // only support paths smaller than 64x64, scaled to less than 256x256
88 // the goal is to accelerate rendering of lots of small paths that may be sc aling 105 // the goal is to accelerate rendering of lots of small paths that may be sc aling
89 SkScalar maxScale = viewMatrix.getMaxScale(); 106 SkScalar maxScale = viewMatrix.getMaxScale();
90 const SkRect& bounds = path.getBounds(); 107 const SkRect& bounds = path.getBounds();
91 SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height()); 108 SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height());
92 return maxDim < 64.f && maxDim*maxScale < 256.f; 109 return maxDim < 64.f && maxDim * maxScale < 256.f;
93 } 110 }
94 111
95 112
96 GrPathRenderer::StencilSupport 113 GrPathRenderer::StencilSupport
97 GrAADistanceFieldPathRenderer::onGetStencilSupport(const GrDrawTarget*, 114 GrAADistanceFieldPathRenderer::onGetStencilSupport(const GrDrawTarget*,
98 const GrPipelineBuilder*, 115 const GrPipelineBuilder*,
99 const SkPath&, 116 const SkPath&,
100 const SkStrokeRec&) const { 117 const SkStrokeRec&) const {
101 return GrPathRenderer::kNoSupport_StencilSupport; 118 return GrPathRenderer::kNoSupport_StencilSupport;
102 } 119 }
103 120
104 //////////////////////////////////////////////////////////////////////////////// 121 ////////////////////////////////////////////////////////////////////////////////
105 122
123 // padding around path bounds to allow for antialiased pixels
124 static const SkScalar kAntiAliasPad = 1.0f;
125
126 class AADistanceFieldPathBatch : public GrBatch {
127 public:
128 typedef GrAADistanceFieldPathRenderer::PathData PathData;
129 typedef SkTDynamicHash<PathData, PathData::Key> PathCache;
130 typedef GrAADistanceFieldPathRenderer::PathDataList PathDataList;
131
132 struct Geometry {
133 Geometry(const SkStrokeRec& stroke) : fStroke(stroke) {}
134 SkPath fPath;
135 SkStrokeRec fStroke;
136 bool fAntiAlias;
137 PathData* fPathData;
138 };
139
140 static GrBatch* Create(const Geometry& geometry, GrColor color, const SkMatr ix& viewMatrix,
141 GrBatchAtlas* atlas, PathCache* pathCache, PathDataLi st* pathList) {
142 return SkNEW_ARGS(AADistanceFieldPathBatch, (geometry, color, viewMatrix ,
143 atlas, pathCache, pathList) );
144 }
145
146 const char* name() const SK_OVERRIDE { return "AADistanceFieldPathBatch"; }
147
148 void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE {
149 out->setKnownFourComponents(fBatch.fColor);
150 }
151
152 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRID E {
153 out->setUnknownSingleComponent();
154 }
155
156 void initBatchTracker(const GrPipelineInfo& init) SK_OVERRIDE {
157 // Handle any color overrides
158 if (init.fColorIgnored) {
159 fBatch.fColor = GrColor_ILLEGAL;
160 } else if (GrColor_ILLEGAL != init.fOverrideColor) {
161 fBatch.fColor = init.fOverrideColor;
162 }
163
164 // setup batch properties
165 fBatch.fColorIgnored = init.fColorIgnored;
166 fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
167 fBatch.fCoverageIgnored = init.fCoverageIgnored;
168 }
169
170 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline ) SK_OVERRIDE {
171 int instanceCount = fGeoData.count();
172
173 SkMatrix invert;
174 if (this->usesLocalCoords() && !this->viewMatrix().invert(&invert)) {
175 SkDebugf("Could not invert viewmatrix\n");
176 return;
177 }
178
179 uint32_t flags = 0;
180 flags |= this->viewMatrix().isSimilarity() ? kSimilarity_DistanceFieldEf fectFlag : 0;
181
182 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBil erp_FilterMode);
183
184 // Setup GrGeometryProcessor
185 GrBatchAtlas* atlas = fAtlas;
186 SkAutoTUnref<GrGeometryProcessor> dfProcessor(
187 GrDistanceFieldNoGammaTextureEffect::Create(this->color(),
188 this->viewMatrix(),
189 atlas->getTexture(),
190 params,
191 flags,
192 false));
193
194 this->initDraw(batchTarget, dfProcessor, pipeline);
195
196 // allocate vertices
197 size_t vertexStride = dfProcessor->getVertexStride();
198 SkASSERT(vertexStride == 2 * sizeof(SkPoint));
199
200 int vertexCount = GrBatchTarget::kVertsPerRect * instanceCount;
201
202 const GrVertexBuffer* vertexBuffer;
203 int firstVertex;
204
205 void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
206 vertexCount,
207 &vertexBuffer,
208 &firstVertex);
209
210 if (!vertices) {
211 SkDebugf("Could not allocate vertices\n");
212 return;
213 }
214
215 // We may have to flush while uploading path data to the atlas, so we se t up the draw here
216 const GrIndexBuffer* quadIndexBuffer = batchTarget->quadIndexBuffer();
217 int maxInstancesPerDraw = quadIndexBuffer->maxQuads();
218
219 GrDrawTarget::DrawInfo drawInfo;
220 drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
221 drawInfo.setStartVertex(0);
222 drawInfo.setStartIndex(0);
223 drawInfo.setVerticesPerInstance(GrBatchTarget::kVertsPerRect);
224 drawInfo.setIndicesPerInstance(GrBatchTarget::kIndicesPerRect);
225 drawInfo.adjustStartVertex(firstVertex);
226 drawInfo.setVertexBuffer(vertexBuffer);
227 drawInfo.setIndexBuffer(quadIndexBuffer);
228
229 int instancesToFlush = 0;
230 for (int i = 0; i < instanceCount; i++) {
231 Geometry& args = fGeoData[i];
232
233 // get mip level
234 SkScalar maxScale = this->viewMatrix().getMaxScale();
235 const SkRect& bounds = args.fPath.getBounds();
236 SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height());
237 SkScalar size = maxScale * maxDim;
238 uint32_t desiredDimension;
239 if (size <= kSmallMIP) {
240 desiredDimension = kSmallMIP;
241 } else if (size <= kMediumMIP) {
242 desiredDimension = kMediumMIP;
243 } else {
244 desiredDimension = kLargeMIP;
245 }
246
247 // check to see if path is cached
248 // TODO: handle stroked vs. filled version of same path
249 PathData::Key key = { args.fPath.getGenerationID(), desiredDimension };
250 args.fPathData = fPathCache->find(key);
251 if (NULL == args.fPathData || !atlas->hasID(args.fPathData->fID)) {
252 // Remove the stale cache entry
253 if (args.fPathData) {
254 fPathCache->remove(args.fPathData->fKey);
255 fPathList->remove(args.fPathData);
256 SkDELETE(args.fPathData);
257 }
258 SkScalar scale = desiredDimension/maxDim;
259 args.fPathData = SkNEW(PathData);
260 if (!this->addPathToAtlas(batchTarget,
261 dfProcessor,
262 pipeline,
263 &drawInfo,
264 &instancesToFlush,
265 maxInstancesPerDraw,
266 atlas,
267 args.fPathData,
268 args.fPath,
269 args.fStroke,
270 args.fAntiAlias,
271 desiredDimension,
272 scale)) {
273 SkDebugf("Can't rasterize path\n");
274 return;
275 }
276 }
277
278 atlas->setLastRefToken(args.fPathData->fID, batchTarget->currentToke n());
279
280 // Now set vertices
281 intptr_t offset = reinterpret_cast<intptr_t>(vertices);
282 offset += i * GrBatchTarget::kVertsPerRect * vertexStride;
283 SkPoint* positions = reinterpret_cast<SkPoint*>(offset);
284 this->drawPath(batchTarget,
285 atlas,
286 pipeline,
287 dfProcessor,
288 positions,
289 vertexStride,
290 this->viewMatrix(),
291 args.fPath,
292 args.fPathData);
293 instancesToFlush++;
294 }
295
296 this->flush(batchTarget, dfProcessor, pipeline, &drawInfo, instancesToFl ush,
297 maxInstancesPerDraw);
298 }
299
300 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
301
302 private:
303 AADistanceFieldPathBatch(const Geometry& geometry, GrColor color, const SkMa trix& viewMatrix,
304 GrBatchAtlas* atlas,
305 PathCache* pathCache, PathDataList* pathList) {
306 this->initClassID<AADistanceFieldPathBatch>();
307 fBatch.fColor = color;
308 fBatch.fViewMatrix = viewMatrix;
309 fGeoData.push_back(geometry);
310 fGeoData.back().fPathData = NULL;
311
312 fAtlas = atlas;
313 fPathCache = pathCache;
314 fPathList = pathList;
315 }
316
317 bool addPathToAtlas(GrBatchTarget* batchTarget,
318 const GrGeometryProcessor* dfProcessor,
319 const GrPipeline* pipeline,
320 GrDrawTarget::DrawInfo* drawInfo,
321 int* instancesToFlush,
322 int maxInstancesPerDraw,
323 GrBatchAtlas* atlas,
324 PathData* pathData,
325 const SkPath& path,
326 const SkStrokeRec&
327 stroke, bool antiAlias,
328 uint32_t dimension,
329 SkScalar scale) {
330 const SkRect& bounds = path.getBounds();
331
332 // generate bounding rect for bitmap draw
333 SkRect scaledBounds = bounds;
334 // scale to mip level size
335 scaledBounds.fLeft *= scale;
336 scaledBounds.fTop *= scale;
337 scaledBounds.fRight *= scale;
338 scaledBounds.fBottom *= scale;
339 // move the origin to an integer boundary (gives better results)
340 SkScalar dx = SkScalarFraction(scaledBounds.fLeft);
341 SkScalar dy = SkScalarFraction(scaledBounds.fTop);
342 scaledBounds.offset(-dx, -dy);
343 // get integer boundary
344 SkIRect devPathBounds;
345 scaledBounds.roundOut(&devPathBounds);
346 // pad to allow room for antialiasing
347 devPathBounds.outset(SkScalarCeilToInt(kAntiAliasPad), SkScalarCeilToInt (kAntiAliasPad));
348 // move origin to upper left corner
349 devPathBounds.offsetTo(0,0);
350
351 // draw path to bitmap
352 SkMatrix drawMatrix;
353 drawMatrix.setTranslate(-bounds.left(), -bounds.top());
354 drawMatrix.postScale(scale, scale);
355 drawMatrix.postTranslate(kAntiAliasPad, kAntiAliasPad);
356
357 // setup bitmap backing
358 // Now translate so the bound's UL corner is at the origin
359 drawMatrix.postTranslate(-devPathBounds.fLeft * SK_Scalar1,
360 -devPathBounds.fTop * SK_Scalar1);
361 SkIRect pathBounds = SkIRect::MakeWH(devPathBounds.width(),
362 devPathBounds.height());
363
364 SkBitmap bmp;
365 const SkImageInfo bmImageInfo = SkImageInfo::MakeA8(pathBounds.fRight,
366 pathBounds.fBottom);
367 if (!bmp.tryAllocPixels(bmImageInfo)) {
368 return false;
369 }
370
371 sk_bzero(bmp.getPixels(), bmp.getSafeSize());
372
373 // rasterize path
374 SkPaint paint;
375 if (stroke.isHairlineStyle()) {
376 paint.setStyle(SkPaint::kStroke_Style);
377 paint.setStrokeWidth(SK_Scalar1);
378 } else {
379 if (stroke.isFillStyle()) {
380 paint.setStyle(SkPaint::kFill_Style);
381 } else {
382 paint.setStyle(SkPaint::kStroke_Style);
383 paint.setStrokeJoin(stroke.getJoin());
384 paint.setStrokeCap(stroke.getCap());
385 paint.setStrokeWidth(stroke.getWidth());
386 }
387 }
388 paint.setAntiAlias(antiAlias);
389
390 SkDraw draw;
391 sk_bzero(&draw, sizeof(draw));
392
393 SkRasterClip rasterClip;
394 rasterClip.setRect(pathBounds);
395 draw.fRC = &rasterClip;
396 draw.fClip = &rasterClip.bwRgn();
397 draw.fMatrix = &drawMatrix;
398 draw.fBitmap = &bmp;
399
400 draw.drawPathCoverage(path, paint);
401
402 // generate signed distance field
403 devPathBounds.outset(SK_DistanceFieldPad, SK_DistanceFieldPad);
404 int width = devPathBounds.width();
405 int height = devPathBounds.height();
406 // TODO We should really generate this directly into the plot somehow
407 SkAutoSMalloc<1024> dfStorage(width * height * sizeof(unsigned char));
408
409 // Generate signed distance field
410 {
411 SkAutoLockPixels alp(bmp);
412
413 SkGenerateDistanceFieldFromA8Image((unsigned char*)dfStorage.get(),
414 (const unsigned char*)bmp.getPixe ls(),
415 bmp.width(), bmp.height(), bmp.ro wBytes());
416 }
417
418 // add to atlas
419 SkIPoint16 atlasLocation;
420 GrBatchAtlas::AtlasID id;
421 bool success = atlas->addToAtlas(&id, batchTarget, width, height, dfStor age.get(),
422 &atlasLocation);
423 if (!success) {
424 this->flush(batchTarget, dfProcessor, pipeline, drawInfo, *instances ToFlush,
425 maxInstancesPerDraw);
426 this->initDraw(batchTarget, dfProcessor, pipeline);
427 *instancesToFlush = 0;
428
429 SkDEBUGCODE(success =) atlas->addToAtlas(&id, batchTarget, width, he ight,
430 dfStorage.get(), &atlasLoca tion);
431 SkASSERT(success);
432
433 }
434
435 // add to cache
436 pathData->fKey.fGenID = path.getGenerationID();
437 pathData->fKey.fDimension = dimension;
438 pathData->fScale = scale;
439 pathData->fID = id;
440 // change the scaled rect to match the size of the inset distance field
441 scaledBounds.fRight = scaledBounds.fLeft +
442 SkIntToScalar(devPathBounds.width() - 2*SK_DistanceFieldInset);
443 scaledBounds.fBottom = scaledBounds.fTop +
444 SkIntToScalar(devPathBounds.height() - 2*SK_DistanceFieldInset);
445 // shift the origin to the correct place relative to the distance field
446 // need to also restore the fractional translation
447 scaledBounds.offset(-SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPa d + dx,
448 -SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPa d + dy);
449 pathData->fBounds = scaledBounds;
450 // origin we render from is inset from distance field edge
451 atlasLocation.fX += SK_DistanceFieldInset;
452 atlasLocation.fY += SK_DistanceFieldInset;
453 pathData->fAtlasLocation = atlasLocation;
454
455 fPathCache->add(pathData);
456 fPathList->addToTail(pathData);
457 #ifdef DF_PATH_TRACKING
458 ++g_NumCachedPaths;
459 #endif
460 return true;
461 }
462
463 void drawPath(GrBatchTarget* target,
464 GrBatchAtlas* atlas,
465 const GrPipeline* pipeline,
466 const GrGeometryProcessor* gp,
467 SkPoint* positions,
468 size_t vertexStride,
469 const SkMatrix& viewMatrix,
470 const SkPath& path,
471 const PathData* pathData) {
472 GrTexture* texture = atlas->getTexture();
473
474 SkScalar dx = pathData->fBounds.fLeft;
475 SkScalar dy = pathData->fBounds.fTop;
476 SkScalar width = pathData->fBounds.width();
477 SkScalar height = pathData->fBounds.height();
478
479 SkScalar invScale = 1.0f / pathData->fScale;
480 dx *= invScale;
481 dy *= invScale;
482 width *= invScale;
483 height *= invScale;
484
485 SkFixed tx = SkIntToFixed(pathData->fAtlasLocation.fX);
486 SkFixed ty = SkIntToFixed(pathData->fAtlasLocation.fY);
487 SkFixed tw = SkScalarToFixed(pathData->fBounds.width());
488 SkFixed th = SkScalarToFixed(pathData->fBounds.height());
489
490 // vertex positions
491 // TODO make the vertex attributes a struct
492 SkRect r = SkRect::MakeXYWH(dx, dy, width, height);
493 positions->setRectFan(r.left(), r.top(), r.right(), r.bottom(), vertexSt ride);
494
495 // vertex texture coords
496 SkPoint* textureCoords = positions + 1;
497 textureCoords->setRectFan(SkFixedToFloat(texture->texturePriv().normaliz eFixedX(tx)),
498 SkFixedToFloat(texture->texturePriv().normaliz eFixedY(ty)),
499 SkFixedToFloat(texture->texturePriv().normaliz eFixedX(tx + tw)),
500 SkFixedToFloat(texture->texturePriv().normaliz eFixedY(ty + th)),
501 vertexStride);
502 }
503
504 void initDraw(GrBatchTarget* batchTarget,
505 const GrGeometryProcessor* dfProcessor,
506 const GrPipeline* pipeline) {
507 batchTarget->initDraw(dfProcessor, pipeline);
508
509 // TODO remove this when batch is everywhere
510 GrPipelineInfo init;
511 init.fColorIgnored = fBatch.fColorIgnored;
512 init.fOverrideColor = GrColor_ILLEGAL;
513 init.fCoverageIgnored = fBatch.fCoverageIgnored;
514 init.fUsesLocalCoords = this->usesLocalCoords();
515 dfProcessor->initBatchTracker(batchTarget->currentBatchTracker(), init);
516 }
517
518 void flush(GrBatchTarget* batchTarget,
519 const GrGeometryProcessor* dfProcessor,
520 const GrPipeline* pipeline,
521 GrDrawTarget::DrawInfo* drawInfo,
522 int instanceCount,
523 int maxInstancesPerDraw) {
524 while (instanceCount) {
525 drawInfo->setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw ));
526 drawInfo->setVertexCount(drawInfo->instanceCount() * drawInfo->verti cesPerInstance());
527 drawInfo->setIndexCount(drawInfo->instanceCount() * drawInfo->indice sPerInstance());
528
529 batchTarget->draw(*drawInfo);
530
531 drawInfo->setStartVertex(drawInfo->startVertex() + drawInfo->vertexC ount());
532 instanceCount -= drawInfo->instanceCount();
533 }
534 }
535
536 GrColor color() const { return fBatch.fColor; }
537 const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; }
538 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
539
540 bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE {
541 AADistanceFieldPathBatch* that = t->cast<AADistanceFieldPathBatch>();
542
543 // TODO we could actually probably do a bunch of this work on the CPU, i e map viewMatrix,
544 // maybe upload color via attribute
545 if (this->color() != that->color()) {
546 return false;
547 }
548
549 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
550 return false;
551 }
552
553 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin()) ;
554 return true;
555 }
556
557 struct BatchTracker {
558 GrColor fColor;
559 SkMatrix fViewMatrix;
560 bool fUsesLocalCoords;
561 bool fColorIgnored;
562 bool fCoverageIgnored;
563 };
564
565 BatchTracker fBatch;
566 SkSTArray<1, Geometry, true> fGeoData;
567 GrBatchAtlas* fAtlas;
568 PathCache* fPathCache;
569 PathDataList* fPathList;
570 };
571
106 bool GrAADistanceFieldPathRenderer::onDrawPath(GrDrawTarget* target, 572 bool GrAADistanceFieldPathRenderer::onDrawPath(GrDrawTarget* target,
107 GrPipelineBuilder* pipelineBuilde r, 573 GrPipelineBuilder* pipelineBuilde r,
108 GrColor color, 574 GrColor color,
109 const SkMatrix& viewMatrix, 575 const SkMatrix& viewMatrix,
110 const SkPath& path, 576 const SkPath& path,
111 const SkStrokeRec& stroke, 577 const SkStrokeRec& stroke,
112 bool antiAlias) { 578 bool antiAlias) {
113 // we've already bailed on inverse filled paths, so this is safe 579 // we've already bailed on inverse filled paths, so this is safe
114 if (path.isEmpty()) { 580 if (path.isEmpty()) {
115 return true; 581 return true;
116 } 582 }
117 583
118 SkASSERT(fContext); 584 SkASSERT(fContext);
119 585
120 // get mip level 586 if (!fAtlas) {
121 SkScalar maxScale = viewMatrix.getMaxScale(); 587 // Create a new atlas
122 const SkRect& bounds = path.getBounds(); 588 GrSurfaceDesc desc;
123 SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height()); 589 desc.fFlags = kNone_GrSurfaceFlags;
124 SkScalar size = maxScale*maxDim; 590 desc.fWidth = ATLAS_TEXTURE_WIDTH;
125 uint32_t desiredDimension; 591 desc.fHeight = ATLAS_TEXTURE_HEIGHT;
126 if (size <= kSmallMIP) { 592 desc.fConfig = kAlpha_8_GrPixelConfig;
127 desiredDimension = kSmallMIP; 593
128 } else if (size <= kMediumMIP) { 594 // We don't want to flush the context so we claim we're in the middle of flushing so as to
129 desiredDimension = kMediumMIP; 595 // guarantee we do not recieve a texture with pending IO
130 } else { 596 GrTexture* texture = fContext->refScratchTexture(desc, GrContext::kAppro x_ScratchTexMatch,
131 desiredDimension = kLargeMIP; 597 true);
132 } 598 if (texture) {
133 599 fAtlas = SkNEW_ARGS(GrBatchAtlas, (texture, NUM_PLOTS_X, NUM_PLOTS_Y ));
134 // check to see if path is cached 600 } else {
135 // TODO: handle stroked vs. filled version of same path
136 PathData::Key key = { path.getGenerationID(), desiredDimension };
137 PathData* pathData = fPathCache.find(key);
138 if (NULL == pathData) {
139 SkScalar scale = desiredDimension/maxDim;
140 pathData = this->addPathToAtlas(path, stroke, antiAlias, desiredDimensio n, scale);
141 if (NULL == pathData) {
142 return false; 601 return false;
143 } 602 }
144 } 603 fAtlas->registerEvictionCallback(&GrAADistanceFieldPathRenderer::HandleE viction,
145 604 (void*)this);
146 // use signed distance field to render 605 }
147 return this->internalDrawPath(target, pipelineBuilder, color, viewMatrix, pa th, pathData); 606
148 } 607 AADistanceFieldPathBatch::Geometry geometry(stroke);
149 608 geometry.fPath = path;
150 // padding around path bounds to allow for antialiased pixels 609 geometry.fAntiAlias = antiAlias;
151 const SkScalar kAntiAliasPad = 1.0f; 610
152 611 SkAutoTUnref<GrBatch> batch(AADistanceFieldPathBatch::Create(geometry, color , viewMatrix,
153 inline bool GrAADistanceFieldPathRenderer::uploadPath(GrPlot** plot, SkIPoint16* atlasLocation, 612 fAtlas, &fPathC ache, &fPathList));
154 int width, int height, voi d* dfStorage) { 613
155 *plot = fAtlas->addToAtlas(&fPlotUsage, width, height, dfStorage, atlasLocat ion); 614 SkRect bounds = path.getBounds();
156 615 viewMatrix.mapRect(&bounds);
157 // if atlas full 616 target->drawBatch(pipelineBuilder, batch, &bounds);
158 if (NULL == *plot) { 617
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; 618 return true;
185 } 619 }
186 620
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
« no previous file with comments | « src/gpu/GrAADistanceFieldPathRenderer.h ('k') | src/gpu/GrBatch.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698