| Index: src/gpu/GrAADistanceFieldPathRenderer.cpp
|
| diff --git a/src/gpu/GrAADistanceFieldPathRenderer.cpp b/src/gpu/GrAADistanceFieldPathRenderer.cpp
|
| deleted file mode 100644
|
| index 45a3d65179c916ad1d4727975ea0b42ba81bb9c5..0000000000000000000000000000000000000000
|
| --- a/src/gpu/GrAADistanceFieldPathRenderer.cpp
|
| +++ /dev/null
|
| @@ -1,626 +0,0 @@
|
| -
|
| -/*
|
| - * Copyright 2014 Google Inc.
|
| - *
|
| - * Use of this source code is governed by a BSD-style license that can be
|
| - * found in the LICENSE file.
|
| - */
|
| -
|
| -#include "GrAADistanceFieldPathRenderer.h"
|
| -
|
| -#include "GrBatchFlushState.h"
|
| -#include "GrBatchTest.h"
|
| -#include "GrContext.h"
|
| -#include "GrPipelineBuilder.h"
|
| -#include "GrResourceProvider.h"
|
| -#include "GrSurfacePriv.h"
|
| -#include "GrSWMaskHelper.h"
|
| -#include "GrTexturePriv.h"
|
| -#include "GrVertexBuffer.h"
|
| -#include "batches/GrVertexBatch.h"
|
| -#include "effects/GrDistanceFieldGeoProc.h"
|
| -
|
| -#include "SkDistanceFieldGen.h"
|
| -#include "SkRTConf.h"
|
| -
|
| -#define ATLAS_TEXTURE_WIDTH 1024
|
| -#define ATLAS_TEXTURE_HEIGHT 2048
|
| -#define PLOT_WIDTH 256
|
| -#define PLOT_HEIGHT 256
|
| -
|
| -#define NUM_PLOTS_X (ATLAS_TEXTURE_WIDTH / PLOT_WIDTH)
|
| -#define NUM_PLOTS_Y (ATLAS_TEXTURE_HEIGHT / PLOT_HEIGHT)
|
| -
|
| -#ifdef DF_PATH_TRACKING
|
| -static int g_NumCachedPaths = 0;
|
| -static int g_NumFreedPaths = 0;
|
| -#endif
|
| -
|
| -// mip levels
|
| -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);
|
| - delete pathData;
|
| -#ifdef DF_PATH_TRACKING
|
| - ++g_NumFreedPaths;
|
| -#endif
|
| - }
|
| - }
|
| -}
|
| -
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -GrAADistanceFieldPathRenderer::GrAADistanceFieldPathRenderer() : fAtlas(nullptr) {}
|
| -
|
| -GrAADistanceFieldPathRenderer::~GrAADistanceFieldPathRenderer() {
|
| - PathDataList::Iter iter;
|
| - iter.init(fPathList, PathDataList::Iter::kHead_IterStart);
|
| - PathData* pathData;
|
| - while ((pathData = iter.get())) {
|
| - iter.next();
|
| - fPathList.remove(pathData);
|
| - delete pathData;
|
| - }
|
| - delete fAtlas;
|
| -
|
| -#ifdef DF_PATH_TRACKING
|
| - SkDebugf("Cached paths: %d, freed paths: %d\n", g_NumCachedPaths, g_NumFreedPaths);
|
| -#endif
|
| -}
|
| -
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -bool GrAADistanceFieldPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
|
| -
|
| - // TODO: Support inverse fill
|
| - // TODO: Support strokes
|
| - if (!args.fShaderCaps->shaderDerivativeSupport() || !args.fAntiAlias ||
|
| - args.fPath->isInverseFillType() || args.fPath->isVolatile() ||
|
| - !args.fStroke->isFillStyle()) {
|
| - return false;
|
| - }
|
| -
|
| - // currently don't support perspective
|
| - if (args.fViewMatrix->hasPerspective()) {
|
| - return false;
|
| - }
|
| -
|
| - // only support paths smaller than 64x64, scaled to less than 256x256
|
| - // the goal is to accelerate rendering of lots of small paths that may be scaling
|
| - SkScalar maxScale = args.fViewMatrix->getMaxScale();
|
| - const SkRect& bounds = args.fPath->getBounds();
|
| - SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height());
|
| - return maxDim < 64.f && maxDim * maxScale < 256.f;
|
| -}
|
| -
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -
|
| -// padding around path bounds to allow for antialiased pixels
|
| -static const SkScalar kAntiAliasPad = 1.0f;
|
| -
|
| -class AADistanceFieldPathBatch : public GrVertexBatch {
|
| -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 GrDrawBatch* Create(const Geometry& geometry, GrColor color, const SkMatrix& viewMatrix,
|
| - GrBatchAtlas* atlas, PathCache* pathCache, PathDataList* pathList) {
|
| - return new AADistanceFieldPathBatch(geometry, color, viewMatrix, atlas, pathCache,
|
| - pathList);
|
| - }
|
| -
|
| - const char* name() const override { return "AADistanceFieldPathBatch"; }
|
| -
|
| - void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
|
| - out->setKnownFourComponents(fBatch.fColor);
|
| - }
|
| -
|
| - void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
|
| - out->setUnknownSingleComponent();
|
| - }
|
| -
|
| -private:
|
| - void initBatchTracker(const GrPipelineOptimizations& opt) override {
|
| - // Handle any color overrides
|
| - if (!opt.readsColor()) {
|
| - fBatch.fColor = GrColor_ILLEGAL;
|
| - }
|
| - opt.getOverrideColorIfSet(&fBatch.fColor);
|
| -
|
| - // setup batch properties
|
| - fBatch.fColorIgnored = !opt.readsColor();
|
| - fBatch.fUsesLocalCoords = opt.readsLocalCoords();
|
| - fBatch.fCoverageIgnored = !opt.readsCoverage();
|
| - }
|
| -
|
| - struct FlushInfo {
|
| - SkAutoTUnref<const GrVertexBuffer> fVertexBuffer;
|
| - SkAutoTUnref<const GrIndexBuffer> fIndexBuffer;
|
| - int fVertexOffset;
|
| - int fInstancesToFlush;
|
| - };
|
| -
|
| - void onPrepareDraws(Target* target) override {
|
| - int instanceCount = fGeoData.count();
|
| -
|
| - SkMatrix invert;
|
| - if (this->usesLocalCoords() && !this->viewMatrix().invert(&invert)) {
|
| - SkDebugf("Could not invert viewmatrix\n");
|
| - return;
|
| - }
|
| -
|
| - 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(
|
| - GrDistanceFieldPathGeoProc::Create(this->color(),
|
| - this->viewMatrix(),
|
| - atlas->getTexture(),
|
| - params,
|
| - flags,
|
| - this->usesLocalCoords()));
|
| -
|
| - target->initDraw(dfProcessor, this->pipeline());
|
| -
|
| - FlushInfo flushInfo;
|
| -
|
| - // allocate vertices
|
| - size_t vertexStride = dfProcessor->getVertexStride();
|
| - SkASSERT(vertexStride == 2 * sizeof(SkPoint));
|
| -
|
| - const GrVertexBuffer* vertexBuffer;
|
| - void* vertices = target->makeVertexSpace(vertexStride,
|
| - kVerticesPerQuad * instanceCount,
|
| - &vertexBuffer,
|
| - &flushInfo.fVertexOffset);
|
| - flushInfo.fVertexBuffer.reset(SkRef(vertexBuffer));
|
| - flushInfo.fIndexBuffer.reset(target->resourceProvider()->refQuadIndexBuffer());
|
| - if (!vertices || !flushInfo.fIndexBuffer) {
|
| - SkDebugf("Could not allocate vertices\n");
|
| - return;
|
| - }
|
| -
|
| - flushInfo.fInstancesToFlush = 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;
|
| - }
|
| -
|
| - // 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 (nullptr == args.fPathData || !atlas->hasID(args.fPathData->fID)) {
|
| - // Remove the stale cache entry
|
| - if (args.fPathData) {
|
| - fPathCache->remove(args.fPathData->fKey);
|
| - fPathList->remove(args.fPathData);
|
| - delete args.fPathData;
|
| - }
|
| - SkScalar scale = desiredDimension/maxDim;
|
| - args.fPathData = new PathData;
|
| - if (!this->addPathToAtlas(target,
|
| - dfProcessor,
|
| - this->pipeline(),
|
| - &flushInfo,
|
| - atlas,
|
| - args.fPathData,
|
| - args.fPath,
|
| - args.fStroke,
|
| - args.fAntiAlias,
|
| - desiredDimension,
|
| - scale)) {
|
| - SkDebugf("Can't rasterize path\n");
|
| - return;
|
| - }
|
| - }
|
| -
|
| - atlas->setLastUseToken(args.fPathData->fID, target->currentToken());
|
| -
|
| - // Now set vertices
|
| - intptr_t offset = reinterpret_cast<intptr_t>(vertices);
|
| - offset += i * kVerticesPerQuad * vertexStride;
|
| - SkPoint* positions = reinterpret_cast<SkPoint*>(offset);
|
| - this->writePathVertices(target,
|
| - atlas,
|
| - this->pipeline(),
|
| - dfProcessor,
|
| - positions,
|
| - vertexStride,
|
| - this->viewMatrix(),
|
| - args.fPath,
|
| - args.fPathData);
|
| - flushInfo.fInstancesToFlush++;
|
| - }
|
| -
|
| - this->flush(target, &flushInfo);
|
| - }
|
| -
|
| - SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
|
| -
|
| - 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 = nullptr;
|
| -
|
| - fAtlas = atlas;
|
| - fPathCache = pathCache;
|
| - fPathList = pathList;
|
| -
|
| - // Compute bounds
|
| - fBounds = geometry.fPath.getBounds();
|
| - viewMatrix.mapRect(&fBounds);
|
| - }
|
| -
|
| - bool addPathToAtlas(GrVertexBatch::Target* target,
|
| - const GrGeometryProcessor* dfProcessor,
|
| - const GrPipeline* pipeline,
|
| - FlushInfo* flushInfo,
|
| - 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());
|
| -
|
| - SkAutoPixmapStorage dst;
|
| - if (!dst.tryAlloc(SkImageInfo::MakeA8(pathBounds.width(),
|
| - pathBounds.height()))) {
|
| - return false;
|
| - }
|
| - sk_bzero(dst.writable_addr(), dst.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.fDst = dst;
|
| -
|
| - 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
|
| - SkGenerateDistanceFieldFromA8Image((unsigned char*)dfStorage.get(),
|
| - (const unsigned char*)dst.addr(),
|
| - dst.width(), dst.height(), dst.rowBytes());
|
| -
|
| - // add to atlas
|
| - SkIPoint16 atlasLocation;
|
| - GrBatchAtlas::AtlasID id;
|
| - bool success = atlas->addToAtlas(&id, target, width, height, dfStorage.get(),
|
| - &atlasLocation);
|
| - if (!success) {
|
| - this->flush(target, flushInfo);
|
| - target->initDraw(dfProcessor, pipeline);
|
| -
|
| - SkDEBUGCODE(success =) atlas->addToAtlas(&id, target, 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;
|
| -#endif
|
| - return true;
|
| - }
|
| -
|
| - void writePathVertices(GrDrawBatch::Target* 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);
|
| - }
|
| -
|
| - void flush(GrVertexBatch::Target* target, FlushInfo* flushInfo) {
|
| - GrVertices vertices;
|
| - int maxInstancesPerDraw = flushInfo->fIndexBuffer->maxQuads();
|
| - vertices.initInstanced(kTriangles_GrPrimitiveType, flushInfo->fVertexBuffer,
|
| - flushInfo->fIndexBuffer, flushInfo->fVertexOffset, kVerticesPerQuad,
|
| - kIndicesPerQuad, flushInfo->fInstancesToFlush, maxInstancesPerDraw);
|
| - target->draw(vertices);
|
| - flushInfo->fVertexOffset += kVerticesPerQuad * flushInfo->fInstancesToFlush;
|
| - flushInfo->fInstancesToFlush = 0;
|
| - }
|
| -
|
| - GrColor color() const { return fBatch.fColor; }
|
| - const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; }
|
| - bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
|
| -
|
| - bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
|
| - AADistanceFieldPathBatch* that = t->cast<AADistanceFieldPathBatch>();
|
| - if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
|
| - that->bounds(), caps)) {
|
| - return false;
|
| - }
|
| -
|
| - // 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());
|
| - this->joinBounds(that->bounds());
|
| - return true;
|
| - }
|
| -
|
| - 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(const DrawPathArgs& args) {
|
| - // we've already bailed on inverse filled paths, so this is safe
|
| - if (args.fPath->isEmpty()) {
|
| - return true;
|
| - }
|
| -
|
| - if (!fAtlas) {
|
| - fAtlas = args.fResourceProvider->createAtlas(kAlpha_8_GrPixelConfig,
|
| - ATLAS_TEXTURE_WIDTH, ATLAS_TEXTURE_HEIGHT,
|
| - NUM_PLOTS_X, NUM_PLOTS_Y,
|
| - &GrAADistanceFieldPathRenderer::HandleEviction,
|
| - (void*)this);
|
| - if (!fAtlas) {
|
| - return false;
|
| - }
|
| - }
|
| -
|
| - AADistanceFieldPathBatch::Geometry geometry(*args.fStroke);
|
| - geometry.fPath = *args.fPath;
|
| - geometry.fAntiAlias = args.fAntiAlias;
|
| -
|
| - SkAutoTUnref<GrDrawBatch> batch(AADistanceFieldPathBatch::Create(geometry, args.fColor,
|
| - *args.fViewMatrix, fAtlas,
|
| - &fPathCache, &fPathList));
|
| - args.fTarget->drawBatch(*args.fPipelineBuilder, batch);
|
| -
|
| - return true;
|
| -}
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////////////////////////
|
| -
|
| -#ifdef GR_TEST_UTILS
|
| -
|
| -struct PathTestStruct {
|
| - typedef GrAADistanceFieldPathRenderer::PathCache PathCache;
|
| - typedef GrAADistanceFieldPathRenderer::PathData PathData;
|
| - typedef GrAADistanceFieldPathRenderer::PathDataList PathDataList;
|
| - PathTestStruct() : fContextID(SK_InvalidGenID), fAtlas(nullptr) {}
|
| - ~PathTestStruct() { this->reset(); }
|
| -
|
| - void reset() {
|
| - PathDataList::Iter iter;
|
| - iter.init(fPathList, PathDataList::Iter::kHead_IterStart);
|
| - PathData* pathData;
|
| - while ((pathData = iter.get())) {
|
| - iter.next();
|
| - fPathList.remove(pathData);
|
| - delete pathData;
|
| - }
|
| - delete fAtlas;
|
| - fPathCache.reset();
|
| - }
|
| -
|
| - static void HandleEviction(GrBatchAtlas::AtlasID id, void* pr) {
|
| - PathTestStruct* dfpr = (PathTestStruct*)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);
|
| - delete pathData;
|
| - }
|
| - }
|
| - }
|
| -
|
| - uint32_t fContextID;
|
| - GrBatchAtlas* fAtlas;
|
| - PathCache fPathCache;
|
| - PathDataList fPathList;
|
| -};
|
| -
|
| -DRAW_BATCH_TEST_DEFINE(AADistanceFieldPathBatch) {
|
| - static PathTestStruct gTestStruct;
|
| -
|
| - if (context->uniqueID() != gTestStruct.fContextID) {
|
| - gTestStruct.fContextID = context->uniqueID();
|
| - gTestStruct.reset();
|
| - gTestStruct.fAtlas =
|
| - context->resourceProvider()->createAtlas(kAlpha_8_GrPixelConfig,
|
| - ATLAS_TEXTURE_WIDTH, ATLAS_TEXTURE_HEIGHT,
|
| - NUM_PLOTS_X, NUM_PLOTS_Y,
|
| - &PathTestStruct::HandleEviction,
|
| - (void*)&gTestStruct);
|
| - }
|
| -
|
| - SkMatrix viewMatrix = GrTest::TestMatrix(random);
|
| - GrColor color = GrRandomColor(random);
|
| -
|
| - AADistanceFieldPathBatch::Geometry geometry(GrTest::TestStrokeRec(random));
|
| - geometry.fPath = GrTest::TestPath(random);
|
| - geometry.fAntiAlias = random->nextBool();
|
| -
|
| - return AADistanceFieldPathBatch::Create(geometry, color, viewMatrix,
|
| - gTestStruct.fAtlas,
|
| - &gTestStruct.fPathCache,
|
| - &gTestStruct.fPathList);
|
| -}
|
| -
|
| -#endif
|
|
|