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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/gpu/GrAADistanceFieldPathRenderer.h ('k') | src/gpu/GrBatch.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/gpu/GrAADistanceFieldPathRenderer.cpp
diff --git a/src/gpu/GrAADistanceFieldPathRenderer.cpp b/src/gpu/GrAADistanceFieldPathRenderer.cpp
index d50af9fbd85829e0b2c9235301f96da65cf7d036..b9ca1ec26b6fc77fcae1b585e97842abc07a1869 100755
--- a/src/gpu/GrAADistanceFieldPathRenderer.cpp
+++ b/src/gpu/GrAADistanceFieldPathRenderer.cpp
@@ -8,7 +8,9 @@
#include "GrAADistanceFieldPathRenderer.h"
-#include "GrAtlas.h"
+#include "GrBatch.h"
+#include "GrBatchTarget.h"
+#include "GrBufferAllocPool.h"
#include "GrContext.h"
#include "GrPipelineBuilder.h"
#include "GrSurfacePriv.h"
@@ -27,9 +29,6 @@
#define NUM_PLOTS_X (ATLAS_TEXTURE_WIDTH / PLOT_WIDTH)
#define NUM_PLOTS_Y (ATLAS_TEXTURE_HEIGHT / PLOT_HEIGHT)
-SK_CONF_DECLARE(bool, c_DumpPathCache, "gpu.dumpPathCache", false,
- "Dump the contents of the path cache before every purge.");
-
#ifdef DF_PATH_TRACKING
static int g_NumCachedPaths = 0;
static int g_NumFreedPaths = 0;
@@ -40,11 +39,30 @@ static const int kSmallMIP = 32;
static const int kMediumMIP = 78;
static const int kLargeMIP = 192;
+// Callback to clear out internal path cache when eviction occurs
+void GrAADistanceFieldPathRenderer::HandleEviction(GrBatchAtlas::AtlasID id, void* pr) {
+ GrAADistanceFieldPathRenderer* dfpr = (GrAADistanceFieldPathRenderer*)pr;
+ // remove any paths that use this plot
+ PathDataList::Iter iter;
+ iter.init(dfpr->fPathList, PathDataList::Iter::kHead_IterStart);
+ PathData* pathData;
+ while ((pathData = iter.get())) {
+ iter.next();
+ if (id == pathData->fID) {
+ dfpr->fPathCache.remove(pathData->fKey);
+ dfpr->fPathList.remove(pathData);
+ SkDELETE(pathData);
+#ifdef DF_PATH_TRACKING
+ ++g_NumFreedPaths;
+#endif
+ }
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
GrAADistanceFieldPathRenderer::GrAADistanceFieldPathRenderer(GrContext* context)
: fContext(context)
- , fAtlas(NULL)
- , fEffectFlags(kInvalid_DistanceFieldEffectFlag) {
+ , fAtlas(NULL) {
}
GrAADistanceFieldPathRenderer::~GrAADistanceFieldPathRenderer() {
@@ -56,7 +74,6 @@ GrAADistanceFieldPathRenderer::~GrAADistanceFieldPathRenderer() {
fPathList.remove(pathData);
SkDELETE(pathData);
}
-
SkDELETE(fAtlas);
#ifdef DF_PATH_TRACKING
@@ -89,7 +106,7 @@ bool GrAADistanceFieldPathRenderer::canDrawPath(const GrDrawTarget* target,
SkScalar maxScale = viewMatrix.getMaxScale();
const SkRect& bounds = path.getBounds();
SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height());
- return maxDim < 64.f && maxDim*maxScale < 256.f;
+ return maxDim < 64.f && maxDim * maxScale < 256.f;
}
@@ -103,285 +120,501 @@ GrAADistanceFieldPathRenderer::onGetStencilSupport(const GrDrawTarget*,
////////////////////////////////////////////////////////////////////////////////
-bool GrAADistanceFieldPathRenderer::onDrawPath(GrDrawTarget* target,
- GrPipelineBuilder* pipelineBuilder,
- GrColor color,
- const SkMatrix& viewMatrix,
- const SkPath& path,
- const SkStrokeRec& stroke,
- bool antiAlias) {
- // we've already bailed on inverse filled paths, so this is safe
- if (path.isEmpty()) {
- return true;
+// padding around path bounds to allow for antialiased pixels
+static const SkScalar kAntiAliasPad = 1.0f;
+
+class AADistanceFieldPathBatch : public GrBatch {
+public:
+ typedef GrAADistanceFieldPathRenderer::PathData PathData;
+ typedef SkTDynamicHash<PathData, PathData::Key> PathCache;
+ typedef GrAADistanceFieldPathRenderer::PathDataList PathDataList;
+
+ struct Geometry {
+ Geometry(const SkStrokeRec& stroke) : fStroke(stroke) {}
+ SkPath fPath;
+ SkStrokeRec fStroke;
+ bool fAntiAlias;
+ PathData* fPathData;
+ };
+
+ static GrBatch* Create(const Geometry& geometry, GrColor color, const SkMatrix& viewMatrix,
+ GrBatchAtlas* atlas, PathCache* pathCache, PathDataList* pathList) {
+ return SkNEW_ARGS(AADistanceFieldPathBatch, (geometry, color, viewMatrix,
+ atlas, pathCache, pathList));
}
- SkASSERT(fContext);
+ const char* name() const SK_OVERRIDE { return "AADistanceFieldPathBatch"; }
- // get mip level
- SkScalar maxScale = viewMatrix.getMaxScale();
- const SkRect& bounds = path.getBounds();
- SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height());
- SkScalar size = maxScale*maxDim;
- uint32_t desiredDimension;
- if (size <= kSmallMIP) {
- desiredDimension = kSmallMIP;
- } else if (size <= kMediumMIP) {
- desiredDimension = kMediumMIP;
- } else {
- desiredDimension = kLargeMIP;
+ void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE {
+ out->setKnownFourComponents(fBatch.fColor);
}
- // check to see if path is cached
- // TODO: handle stroked vs. filled version of same path
- PathData::Key key = { path.getGenerationID(), desiredDimension };
- PathData* pathData = fPathCache.find(key);
- if (NULL == pathData) {
- SkScalar scale = desiredDimension/maxDim;
- pathData = this->addPathToAtlas(path, stroke, antiAlias, desiredDimension, scale);
- if (NULL == pathData) {
- return false;
+ void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
+ out->setUnknownSingleComponent();
+ }
+
+ void initBatchTracker(const GrPipelineInfo& init) SK_OVERRIDE {
+ // Handle any color overrides
+ if (init.fColorIgnored) {
+ fBatch.fColor = GrColor_ILLEGAL;
+ } else if (GrColor_ILLEGAL != init.fOverrideColor) {
+ fBatch.fColor = init.fOverrideColor;
}
+
+ // setup batch properties
+ fBatch.fColorIgnored = init.fColorIgnored;
+ fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
+ fBatch.fCoverageIgnored = init.fCoverageIgnored;
}
- // use signed distance field to render
- return this->internalDrawPath(target, pipelineBuilder, color, viewMatrix, path, pathData);
-}
+ void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) SK_OVERRIDE {
+ int instanceCount = fGeoData.count();
-// padding around path bounds to allow for antialiased pixels
-const SkScalar kAntiAliasPad = 1.0f;
-
-inline bool GrAADistanceFieldPathRenderer::uploadPath(GrPlot** plot, SkIPoint16* atlasLocation,
- int width, int height, void* dfStorage) {
- *plot = fAtlas->addToAtlas(&fPlotUsage, width, height, dfStorage, atlasLocation);
-
- // if atlas full
- if (NULL == *plot) {
- if (this->freeUnusedPlot()) {
- *plot = fAtlas->addToAtlas(&fPlotUsage, width, height, dfStorage, atlasLocation);
- if (*plot) {
- return true;
- }
+ SkMatrix invert;
+ if (this->usesLocalCoords() && !this->viewMatrix().invert(&invert)) {
+ SkDebugf("Could not invert viewmatrix\n");
+ return;
}
- if (c_DumpPathCache) {
-#ifdef SK_DEVELOPER
- GrTexture* texture = fAtlas->getTexture();
- texture->surfacePriv().savePixels("pathcache.png");
-#endif
+ uint32_t flags = 0;
+ flags |= this->viewMatrix().isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
+
+ GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_FilterMode);
+
+ // Setup GrGeometryProcessor
+ GrBatchAtlas* atlas = fAtlas;
+ SkAutoTUnref<GrGeometryProcessor> dfProcessor(
+ GrDistanceFieldNoGammaTextureEffect::Create(this->color(),
+ this->viewMatrix(),
+ atlas->getTexture(),
+ params,
+ flags,
+ false));
+
+ this->initDraw(batchTarget, dfProcessor, pipeline);
+
+ // allocate vertices
+ size_t vertexStride = dfProcessor->getVertexStride();
+ SkASSERT(vertexStride == 2 * sizeof(SkPoint));
+
+ int vertexCount = GrBatchTarget::kVertsPerRect * instanceCount;
+
+ const GrVertexBuffer* vertexBuffer;
+ int firstVertex;
+
+ void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
+ vertexCount,
+ &vertexBuffer,
+ &firstVertex);
+
+ if (!vertices) {
+ SkDebugf("Could not allocate vertices\n");
+ return;
}
- // before we purge the cache, we must flush any accumulated draws
- fContext->flush();
+ // We may have to flush while uploading path data to the atlas, so we set up the draw here
+ const GrIndexBuffer* quadIndexBuffer = batchTarget->quadIndexBuffer();
+ int maxInstancesPerDraw = quadIndexBuffer->maxQuads();
+
+ GrDrawTarget::DrawInfo drawInfo;
+ drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
+ drawInfo.setStartVertex(0);
+ drawInfo.setStartIndex(0);
+ drawInfo.setVerticesPerInstance(GrBatchTarget::kVertsPerRect);
+ drawInfo.setIndicesPerInstance(GrBatchTarget::kIndicesPerRect);
+ drawInfo.adjustStartVertex(firstVertex);
+ drawInfo.setVertexBuffer(vertexBuffer);
+ drawInfo.setIndexBuffer(quadIndexBuffer);
+
+ int instancesToFlush = 0;
+ for (int i = 0; i < instanceCount; i++) {
+ Geometry& args = fGeoData[i];
+
+ // get mip level
+ SkScalar maxScale = this->viewMatrix().getMaxScale();
+ const SkRect& bounds = args.fPath.getBounds();
+ SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height());
+ SkScalar size = maxScale * maxDim;
+ uint32_t desiredDimension;
+ if (size <= kSmallMIP) {
+ desiredDimension = kSmallMIP;
+ } else if (size <= kMediumMIP) {
+ desiredDimension = kMediumMIP;
+ } else {
+ desiredDimension = kLargeMIP;
+ }
- if (this->freeUnusedPlot()) {
- *plot = fAtlas->addToAtlas(&fPlotUsage, width, height, dfStorage, atlasLocation);
- if (*plot) {
- return true;
+ // check to see if path is cached
+ // TODO: handle stroked vs. filled version of same path
+ PathData::Key key = { args.fPath.getGenerationID(), desiredDimension };
+ args.fPathData = fPathCache->find(key);
+ if (NULL == args.fPathData || !atlas->hasID(args.fPathData->fID)) {
+ // Remove the stale cache entry
+ if (args.fPathData) {
+ fPathCache->remove(args.fPathData->fKey);
+ fPathList->remove(args.fPathData);
+ SkDELETE(args.fPathData);
+ }
+ SkScalar scale = desiredDimension/maxDim;
+ args.fPathData = SkNEW(PathData);
+ if (!this->addPathToAtlas(batchTarget,
+ dfProcessor,
+ pipeline,
+ &drawInfo,
+ &instancesToFlush,
+ maxInstancesPerDraw,
+ atlas,
+ args.fPathData,
+ args.fPath,
+ args.fStroke,
+ args.fAntiAlias,
+ desiredDimension,
+ scale)) {
+ SkDebugf("Can't rasterize path\n");
+ return;
+ }
}
- }
- return false;
- }
- return true;
-}
-GrAADistanceFieldPathRenderer::PathData* GrAADistanceFieldPathRenderer::addPathToAtlas(
- const SkPath& path,
- const SkStrokeRec& stroke,
- bool antiAlias,
- uint32_t dimension,
- SkScalar scale) {
-
- // generate distance field and add to atlas
- if (NULL == fAtlas) {
- SkISize textureSize = SkISize::Make(ATLAS_TEXTURE_WIDTH, ATLAS_TEXTURE_HEIGHT);
- fAtlas = SkNEW_ARGS(GrAtlas, (fContext->getGpu(), kAlpha_8_GrPixelConfig,
- kNone_GrSurfaceFlags, textureSize,
- NUM_PLOTS_X, NUM_PLOTS_Y, false));
- if (NULL == fAtlas) {
- return NULL;
+ atlas->setLastRefToken(args.fPathData->fID, batchTarget->currentToken());
+
+ // Now set vertices
+ intptr_t offset = reinterpret_cast<intptr_t>(vertices);
+ offset += i * GrBatchTarget::kVertsPerRect * vertexStride;
+ SkPoint* positions = reinterpret_cast<SkPoint*>(offset);
+ this->drawPath(batchTarget,
+ atlas,
+ pipeline,
+ dfProcessor,
+ positions,
+ vertexStride,
+ this->viewMatrix(),
+ args.fPath,
+ args.fPathData);
+ instancesToFlush++;
}
+
+ this->flush(batchTarget, dfProcessor, pipeline, &drawInfo, instancesToFlush,
+ maxInstancesPerDraw);
}
-
- const SkRect& bounds = path.getBounds();
-
- // generate bounding rect for bitmap draw
- SkRect scaledBounds = bounds;
- // scale to mip level size
- scaledBounds.fLeft *= scale;
- scaledBounds.fTop *= scale;
- scaledBounds.fRight *= scale;
- scaledBounds.fBottom *= scale;
- // move the origin to an integer boundary (gives better results)
- SkScalar dx = SkScalarFraction(scaledBounds.fLeft);
- SkScalar dy = SkScalarFraction(scaledBounds.fTop);
- scaledBounds.offset(-dx, -dy);
- // get integer boundary
- SkIRect devPathBounds;
- scaledBounds.roundOut(&devPathBounds);
- // pad to allow room for antialiasing
- devPathBounds.outset(SkScalarCeilToInt(kAntiAliasPad), SkScalarCeilToInt(kAntiAliasPad));
- // move origin to upper left corner
- devPathBounds.offsetTo(0,0);
-
- // draw path to bitmap
- SkMatrix drawMatrix;
- drawMatrix.setTranslate(-bounds.left(), -bounds.top());
- drawMatrix.postScale(scale, scale);
- drawMatrix.postTranslate(kAntiAliasPad, kAntiAliasPad);
- GrSWMaskHelper helper(fContext);
-
- if (!helper.init(devPathBounds, &drawMatrix)) {
- return NULL;
- }
- helper.draw(path, stroke, SkRegion::kReplace_Op, antiAlias, 0xFF);
-
- // generate signed distance field
- devPathBounds.outset(SK_DistanceFieldPad, SK_DistanceFieldPad);
- int width = devPathBounds.width();
- int height = devPathBounds.height();
- SkAutoSMalloc<1024> dfStorage(width*height*sizeof(unsigned char));
- helper.toSDF((unsigned char*) dfStorage.get());
-
- // add to atlas
- GrPlot* plot;
- SkIPoint16 atlasLocation;
- if (!this->uploadPath(&plot, &atlasLocation, width, height, dfStorage.get())) {
- return NULL;
+
+ SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
+
+private:
+ AADistanceFieldPathBatch(const Geometry& geometry, GrColor color, const SkMatrix& viewMatrix,
+ GrBatchAtlas* atlas,
+ PathCache* pathCache, PathDataList* pathList) {
+ this->initClassID<AADistanceFieldPathBatch>();
+ fBatch.fColor = color;
+ fBatch.fViewMatrix = viewMatrix;
+ fGeoData.push_back(geometry);
+ fGeoData.back().fPathData = NULL;
+
+ fAtlas = atlas;
+ fPathCache = pathCache;
+ fPathList = pathList;
}
- // add to cache
- PathData* pathData = SkNEW(PathData);
- pathData->fKey.fGenID = path.getGenerationID();
- pathData->fKey.fDimension = dimension;
- pathData->fScale = scale;
- pathData->fPlot = plot;
- // change the scaled rect to match the size of the inset distance field
- scaledBounds.fRight = scaledBounds.fLeft +
- SkIntToScalar(devPathBounds.width() - 2*SK_DistanceFieldInset);
- scaledBounds.fBottom = scaledBounds.fTop +
- SkIntToScalar(devPathBounds.height() - 2*SK_DistanceFieldInset);
- // shift the origin to the correct place relative to the distance field
- // need to also restore the fractional translation
- scaledBounds.offset(-SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPad + dx,
- -SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPad + dy);
- pathData->fBounds = scaledBounds;
- // origin we render from is inset from distance field edge
- atlasLocation.fX += SK_DistanceFieldInset;
- atlasLocation.fY += SK_DistanceFieldInset;
- pathData->fAtlasLocation = atlasLocation;
-
- fPathCache.add(pathData);
- fPathList.addToTail(pathData);
+ bool addPathToAtlas(GrBatchTarget* batchTarget,
+ const GrGeometryProcessor* dfProcessor,
+ const GrPipeline* pipeline,
+ GrDrawTarget::DrawInfo* drawInfo,
+ int* instancesToFlush,
+ int maxInstancesPerDraw,
+ GrBatchAtlas* atlas,
+ PathData* pathData,
+ const SkPath& path,
+ const SkStrokeRec&
+ stroke, bool antiAlias,
+ uint32_t dimension,
+ SkScalar scale) {
+ const SkRect& bounds = path.getBounds();
+
+ // generate bounding rect for bitmap draw
+ SkRect scaledBounds = bounds;
+ // scale to mip level size
+ scaledBounds.fLeft *= scale;
+ scaledBounds.fTop *= scale;
+ scaledBounds.fRight *= scale;
+ scaledBounds.fBottom *= scale;
+ // move the origin to an integer boundary (gives better results)
+ SkScalar dx = SkScalarFraction(scaledBounds.fLeft);
+ SkScalar dy = SkScalarFraction(scaledBounds.fTop);
+ scaledBounds.offset(-dx, -dy);
+ // get integer boundary
+ SkIRect devPathBounds;
+ scaledBounds.roundOut(&devPathBounds);
+ // pad to allow room for antialiasing
+ devPathBounds.outset(SkScalarCeilToInt(kAntiAliasPad), SkScalarCeilToInt(kAntiAliasPad));
+ // move origin to upper left corner
+ devPathBounds.offsetTo(0,0);
+
+ // draw path to bitmap
+ SkMatrix drawMatrix;
+ drawMatrix.setTranslate(-bounds.left(), -bounds.top());
+ drawMatrix.postScale(scale, scale);
+ drawMatrix.postTranslate(kAntiAliasPad, kAntiAliasPad);
+
+ // setup bitmap backing
+ // Now translate so the bound's UL corner is at the origin
+ drawMatrix.postTranslate(-devPathBounds.fLeft * SK_Scalar1,
+ -devPathBounds.fTop * SK_Scalar1);
+ SkIRect pathBounds = SkIRect::MakeWH(devPathBounds.width(),
+ devPathBounds.height());
+
+ SkBitmap bmp;
+ const SkImageInfo bmImageInfo = SkImageInfo::MakeA8(pathBounds.fRight,
+ pathBounds.fBottom);
+ if (!bmp.tryAllocPixels(bmImageInfo)) {
+ return false;
+ }
+
+ sk_bzero(bmp.getPixels(), bmp.getSafeSize());
+
+ // rasterize path
+ SkPaint paint;
+ if (stroke.isHairlineStyle()) {
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(SK_Scalar1);
+ } else {
+ if (stroke.isFillStyle()) {
+ paint.setStyle(SkPaint::kFill_Style);
+ } else {
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeJoin(stroke.getJoin());
+ paint.setStrokeCap(stroke.getCap());
+ paint.setStrokeWidth(stroke.getWidth());
+ }
+ }
+ paint.setAntiAlias(antiAlias);
+
+ SkDraw draw;
+ sk_bzero(&draw, sizeof(draw));
+
+ SkRasterClip rasterClip;
+ rasterClip.setRect(pathBounds);
+ draw.fRC = &rasterClip;
+ draw.fClip = &rasterClip.bwRgn();
+ draw.fMatrix = &drawMatrix;
+ draw.fBitmap = &bmp;
+
+ draw.drawPathCoverage(path, paint);
+
+ // generate signed distance field
+ devPathBounds.outset(SK_DistanceFieldPad, SK_DistanceFieldPad);
+ int width = devPathBounds.width();
+ int height = devPathBounds.height();
+ // TODO We should really generate this directly into the plot somehow
+ SkAutoSMalloc<1024> dfStorage(width * height * sizeof(unsigned char));
+
+ // Generate signed distance field
+ {
+ SkAutoLockPixels alp(bmp);
+
+ SkGenerateDistanceFieldFromA8Image((unsigned char*)dfStorage.get(),
+ (const unsigned char*)bmp.getPixels(),
+ bmp.width(), bmp.height(), bmp.rowBytes());
+ }
+
+ // add to atlas
+ SkIPoint16 atlasLocation;
+ GrBatchAtlas::AtlasID id;
+ bool success = atlas->addToAtlas(&id, batchTarget, width, height, dfStorage.get(),
+ &atlasLocation);
+ if (!success) {
+ this->flush(batchTarget, dfProcessor, pipeline, drawInfo, *instancesToFlush,
+ maxInstancesPerDraw);
+ this->initDraw(batchTarget, dfProcessor, pipeline);
+ *instancesToFlush = 0;
+
+ SkDEBUGCODE(success =) atlas->addToAtlas(&id, batchTarget, width, height,
+ dfStorage.get(), &atlasLocation);
+ SkASSERT(success);
+
+ }
+
+ // add to cache
+ pathData->fKey.fGenID = path.getGenerationID();
+ pathData->fKey.fDimension = dimension;
+ pathData->fScale = scale;
+ pathData->fID = id;
+ // change the scaled rect to match the size of the inset distance field
+ scaledBounds.fRight = scaledBounds.fLeft +
+ SkIntToScalar(devPathBounds.width() - 2*SK_DistanceFieldInset);
+ scaledBounds.fBottom = scaledBounds.fTop +
+ SkIntToScalar(devPathBounds.height() - 2*SK_DistanceFieldInset);
+ // shift the origin to the correct place relative to the distance field
+ // need to also restore the fractional translation
+ scaledBounds.offset(-SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPad + dx,
+ -SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPad + dy);
+ pathData->fBounds = scaledBounds;
+ // origin we render from is inset from distance field edge
+ atlasLocation.fX += SK_DistanceFieldInset;
+ atlasLocation.fY += SK_DistanceFieldInset;
+ pathData->fAtlasLocation = atlasLocation;
+
+ fPathCache->add(pathData);
+ fPathList->addToTail(pathData);
#ifdef DF_PATH_TRACKING
- ++g_NumCachedPaths;
+ ++g_NumCachedPaths;
#endif
+ return true;
+ }
- return pathData;
-}
+ void drawPath(GrBatchTarget* target,
+ GrBatchAtlas* atlas,
+ const GrPipeline* pipeline,
+ const GrGeometryProcessor* gp,
+ SkPoint* positions,
+ size_t vertexStride,
+ const SkMatrix& viewMatrix,
+ const SkPath& path,
+ const PathData* pathData) {
+ GrTexture* texture = atlas->getTexture();
+
+ SkScalar dx = pathData->fBounds.fLeft;
+ SkScalar dy = pathData->fBounds.fTop;
+ SkScalar width = pathData->fBounds.width();
+ SkScalar height = pathData->fBounds.height();
+
+ SkScalar invScale = 1.0f / pathData->fScale;
+ dx *= invScale;
+ dy *= invScale;
+ width *= invScale;
+ height *= invScale;
+
+ SkFixed tx = SkIntToFixed(pathData->fAtlasLocation.fX);
+ SkFixed ty = SkIntToFixed(pathData->fAtlasLocation.fY);
+ SkFixed tw = SkScalarToFixed(pathData->fBounds.width());
+ SkFixed th = SkScalarToFixed(pathData->fBounds.height());
+
+ // vertex positions
+ // TODO make the vertex attributes a struct
+ SkRect r = SkRect::MakeXYWH(dx, dy, width, height);
+ positions->setRectFan(r.left(), r.top(), r.right(), r.bottom(), vertexStride);
+
+ // vertex texture coords
+ SkPoint* textureCoords = positions + 1;
+ textureCoords->setRectFan(SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx)),
+ SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty)),
+ SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx + tw)),
+ SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty + th)),
+ vertexStride);
+ }
-bool GrAADistanceFieldPathRenderer::freeUnusedPlot() {
- // find an unused plot
- GrPlot* plot = fAtlas->getUnusedPlot();
- if (NULL == plot) {
- return false;
+ void initDraw(GrBatchTarget* batchTarget,
+ const GrGeometryProcessor* dfProcessor,
+ const GrPipeline* pipeline) {
+ batchTarget->initDraw(dfProcessor, pipeline);
+
+ // TODO remove this when batch is everywhere
+ GrPipelineInfo init;
+ init.fColorIgnored = fBatch.fColorIgnored;
+ init.fOverrideColor = GrColor_ILLEGAL;
+ init.fCoverageIgnored = fBatch.fCoverageIgnored;
+ init.fUsesLocalCoords = this->usesLocalCoords();
+ dfProcessor->initBatchTracker(batchTarget->currentBatchTracker(), init);
}
- plot->resetRects();
- // remove any paths that use this plot
- PathDataList::Iter iter;
- iter.init(fPathList, PathDataList::Iter::kHead_IterStart);
- PathData* pathData;
- while ((pathData = iter.get())) {
- iter.next();
- if (plot == pathData->fPlot) {
- fPathCache.remove(pathData->fKey);
- fPathList.remove(pathData);
- SkDELETE(pathData);
-#ifdef DF_PATH_TRACKING
- ++g_NumFreedPaths;
-#endif
+ void flush(GrBatchTarget* batchTarget,
+ const GrGeometryProcessor* dfProcessor,
+ const GrPipeline* pipeline,
+ GrDrawTarget::DrawInfo* drawInfo,
+ int instanceCount,
+ int maxInstancesPerDraw) {
+ while (instanceCount) {
+ drawInfo->setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw));
+ drawInfo->setVertexCount(drawInfo->instanceCount() * drawInfo->verticesPerInstance());
+ drawInfo->setIndexCount(drawInfo->instanceCount() * drawInfo->indicesPerInstance());
+
+ batchTarget->draw(*drawInfo);
+
+ drawInfo->setStartVertex(drawInfo->startVertex() + drawInfo->vertexCount());
+ instanceCount -= drawInfo->instanceCount();
+ }
+ }
+
+ GrColor color() const { return fBatch.fColor; }
+ const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; }
+ bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
+
+ bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE {
+ AADistanceFieldPathBatch* that = t->cast<AADistanceFieldPathBatch>();
+
+ // TODO we could actually probably do a bunch of this work on the CPU, ie map viewMatrix,
+ // maybe upload color via attribute
+ if (this->color() != that->color()) {
+ return false;
+ }
+
+ if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
+ return false;
}
+
+ fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
+ return true;
}
-
- // tell the atlas to free the plot
- GrAtlas::RemovePlot(&fPlotUsage, plot);
-
- return true;
-}
-bool GrAADistanceFieldPathRenderer::internalDrawPath(GrDrawTarget* target,
- GrPipelineBuilder* pipelineBuilder,
- GrColor color,
- const SkMatrix& viewMatrix,
- const SkPath& path,
- const PathData* pathData) {
- GrTexture* texture = fAtlas->getTexture();
- GrPipelineBuilder::AutoRestoreFragmentProcessors arfp(pipelineBuilder);
-
- SkASSERT(pathData->fPlot);
- GrDrawTarget::DrawToken drawToken = target->getCurrentDrawToken();
- pathData->fPlot->setDrawToken(drawToken);
-
- // set up any flags
- uint32_t flags = 0;
- flags |= viewMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
-
- GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_FilterMode);
- if (flags != fEffectFlags || fCachedGeometryProcessor->color() != color ||
- !fCachedGeometryProcessor->viewMatrix().cheapEqualTo(viewMatrix)) {
- fCachedGeometryProcessor.reset(GrDistanceFieldNoGammaTextureEffect::Create(color,
- viewMatrix,
- texture,
- params,
- flags,
- false));
- fEffectFlags = flags;
+ struct BatchTracker {
+ GrColor fColor;
+ SkMatrix fViewMatrix;
+ bool fUsesLocalCoords;
+ bool fColorIgnored;
+ bool fCoverageIgnored;
+ };
+
+ BatchTracker fBatch;
+ SkSTArray<1, Geometry, true> fGeoData;
+ GrBatchAtlas* fAtlas;
+ PathCache* fPathCache;
+ PathDataList* fPathList;
+};
+
+bool GrAADistanceFieldPathRenderer::onDrawPath(GrDrawTarget* target,
+ GrPipelineBuilder* pipelineBuilder,
+ GrColor color,
+ const SkMatrix& viewMatrix,
+ const SkPath& path,
+ const SkStrokeRec& stroke,
+ bool antiAlias) {
+ // we've already bailed on inverse filled paths, so this is safe
+ if (path.isEmpty()) {
+ return true;
}
- void* vertices = NULL;
- bool success = target->reserveVertexAndIndexSpace(4,
- fCachedGeometryProcessor->getVertexStride(),
- 0, &vertices, NULL);
- SkASSERT(fCachedGeometryProcessor->getVertexStride() == 2 * sizeof(SkPoint));
- GrAlwaysAssert(success);
-
- SkScalar dx = pathData->fBounds.fLeft;
- SkScalar dy = pathData->fBounds.fTop;
- SkScalar width = pathData->fBounds.width();
- SkScalar height = pathData->fBounds.height();
-
- SkScalar invScale = 1.0f/pathData->fScale;
- dx *= invScale;
- dy *= invScale;
- width *= invScale;
- height *= invScale;
-
- SkFixed tx = SkIntToFixed(pathData->fAtlasLocation.fX);
- SkFixed ty = SkIntToFixed(pathData->fAtlasLocation.fY);
- SkFixed tw = SkScalarToFixed(pathData->fBounds.width());
- SkFixed th = SkScalarToFixed(pathData->fBounds.height());
-
- // vertex positions
- SkRect r = SkRect::MakeXYWH(dx, dy, width, height);
- size_t vertSize = 2 * sizeof(SkPoint);
- SkPoint* positions = reinterpret_cast<SkPoint*>(vertices);
- positions->setRectFan(r.left(), r.top(), r.right(), r.bottom(), vertSize);
-
- // vertex texture coords
- intptr_t intPtr = reinterpret_cast<intptr_t>(positions);
- SkPoint* textureCoords = reinterpret_cast<SkPoint*>(intPtr + vertSize - sizeof(SkPoint));
- textureCoords->setRectFan(SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx)),
- SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty)),
- SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx + tw)),
- SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty + th)),
- vertSize);
-
- viewMatrix.mapRect(&r);
- target->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
- target->drawIndexedInstances(pipelineBuilder, fCachedGeometryProcessor.get(),
- kTriangles_GrPrimitiveType, 1, 4, 6, &r);
- target->resetVertexSource();
-
+ SkASSERT(fContext);
+
+ if (!fAtlas) {
+ // Create a new atlas
+ GrSurfaceDesc desc;
+ desc.fFlags = kNone_GrSurfaceFlags;
+ desc.fWidth = ATLAS_TEXTURE_WIDTH;
+ desc.fHeight = ATLAS_TEXTURE_HEIGHT;
+ desc.fConfig = kAlpha_8_GrPixelConfig;
+
+ // We don't want to flush the context so we claim we're in the middle of flushing so as to
+ // guarantee we do not recieve a texture with pending IO
+ GrTexture* texture = fContext->refScratchTexture(desc, GrContext::kApprox_ScratchTexMatch,
+ true);
+ if (texture) {
+ fAtlas = SkNEW_ARGS(GrBatchAtlas, (texture, NUM_PLOTS_X, NUM_PLOTS_Y));
+ } else {
+ return false;
+ }
+ fAtlas->registerEvictionCallback(&GrAADistanceFieldPathRenderer::HandleEviction,
+ (void*)this);
+ }
+
+ AADistanceFieldPathBatch::Geometry geometry(stroke);
+ geometry.fPath = path;
+ geometry.fAntiAlias = antiAlias;
+
+ SkAutoTUnref<GrBatch> batch(AADistanceFieldPathBatch::Create(geometry, color, viewMatrix,
+ fAtlas, &fPathCache, &fPathList));
+
+ SkRect bounds = path.getBounds();
+ viewMatrix.mapRect(&bounds);
+ target->drawBatch(pipelineBuilder, batch, &bounds);
+
return true;
}
« 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