blob: e94cd591f3e30925c6b077c58976c4c0af19a828 [file] [log] [blame]
jvanverthfa38a302014-10-06 05:59:05 -07001
2/*
3 * Copyright 2014 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9#include "GrAADistanceFieldPathRenderer.h"
10
bsalomon75398562015-08-17 12:55:38 -070011#include "GrBatchFlushState.h"
joshualitt21279c72015-05-11 07:21:37 -070012#include "GrBatchTest.h"
jvanverthfa38a302014-10-06 05:59:05 -070013#include "GrContext.h"
egdaniel8dd688b2015-01-22 10:16:09 -080014#include "GrPipelineBuilder.h"
bsalomonb5238a72015-05-05 07:49:49 -070015#include "GrResourceProvider.h"
jvanverthfa38a302014-10-06 05:59:05 -070016#include "GrSurfacePriv.h"
17#include "GrSWMaskHelper.h"
18#include "GrTexturePriv.h"
bsalomon72e3ae42015-04-28 08:08:46 -070019#include "GrVertexBuffer.h"
bsalomon16b99132015-08-13 14:55:50 -070020#include "batches/GrVertexBatch.h"
jvanverth8ed3b9a2015-04-09 08:00:49 -070021#include "effects/GrDistanceFieldGeoProc.h"
jvanverthfa38a302014-10-06 05:59:05 -070022
23#include "SkDistanceFieldGen.h"
24#include "SkRTConf.h"
25
jvanverthfb1e2fc2015-09-15 13:11:11 -070026#define ATLAS_TEXTURE_WIDTH 2048
jvanverthb61283f2014-10-30 05:57:21 -070027#define ATLAS_TEXTURE_HEIGHT 2048
jvanverthfb1e2fc2015-09-15 13:11:11 -070028#define PLOT_WIDTH 512
reede4ef1ca2015-02-17 18:38:38 -080029#define PLOT_HEIGHT 256
jvanverthfa38a302014-10-06 05:59:05 -070030
31#define NUM_PLOTS_X (ATLAS_TEXTURE_WIDTH / PLOT_WIDTH)
32#define NUM_PLOTS_Y (ATLAS_TEXTURE_HEIGHT / PLOT_HEIGHT)
33
jvanverthb3eb6872014-10-24 07:12:51 -070034#ifdef DF_PATH_TRACKING
35static int g_NumCachedPaths = 0;
36static int g_NumFreedPaths = 0;
37#endif
38
jvanverthb61283f2014-10-30 05:57:21 -070039// mip levels
40static const int kSmallMIP = 32;
jvanverth512e4372015-11-23 11:50:02 -080041static const int kMediumMIP = 73;
jvanverthfb1e2fc2015-09-15 13:11:11 -070042static const int kLargeMIP = 162;
jvanverthb61283f2014-10-30 05:57:21 -070043
joshualitt5bf99f12015-03-13 11:47:42 -070044// Callback to clear out internal path cache when eviction occurs
45void GrAADistanceFieldPathRenderer::HandleEviction(GrBatchAtlas::AtlasID id, void* pr) {
46 GrAADistanceFieldPathRenderer* dfpr = (GrAADistanceFieldPathRenderer*)pr;
47 // remove any paths that use this plot
48 PathDataList::Iter iter;
49 iter.init(dfpr->fPathList, PathDataList::Iter::kHead_IterStart);
50 PathData* pathData;
51 while ((pathData = iter.get())) {
52 iter.next();
53 if (id == pathData->fID) {
54 dfpr->fPathCache.remove(pathData->fKey);
55 dfpr->fPathList.remove(pathData);
halcanary385fe4d2015-08-26 13:07:48 -070056 delete pathData;
joshualitt5bf99f12015-03-13 11:47:42 -070057#ifdef DF_PATH_TRACKING
58 ++g_NumFreedPaths;
59#endif
60 }
61 }
62}
63
jvanverthfa38a302014-10-06 05:59:05 -070064////////////////////////////////////////////////////////////////////////////////
halcanary96fcdcc2015-08-27 07:41:13 -070065GrAADistanceFieldPathRenderer::GrAADistanceFieldPathRenderer() : fAtlas(nullptr) {}
jvanverth6d22eca2014-10-28 11:10:48 -070066
jvanverthfa38a302014-10-06 05:59:05 -070067GrAADistanceFieldPathRenderer::~GrAADistanceFieldPathRenderer() {
68 PathDataList::Iter iter;
69 iter.init(fPathList, PathDataList::Iter::kHead_IterStart);
70 PathData* pathData;
71 while ((pathData = iter.get())) {
72 iter.next();
73 fPathList.remove(pathData);
halcanary385fe4d2015-08-26 13:07:48 -070074 delete pathData;
jvanverthfa38a302014-10-06 05:59:05 -070075 }
halcanary385fe4d2015-08-26 13:07:48 -070076 delete fAtlas;
jvanverthb3eb6872014-10-24 07:12:51 -070077
78#ifdef DF_PATH_TRACKING
79 SkDebugf("Cached paths: %d, freed paths: %d\n", g_NumCachedPaths, g_NumFreedPaths);
80#endif
jvanverthfa38a302014-10-06 05:59:05 -070081}
82
83////////////////////////////////////////////////////////////////////////////////
bsalomon0aff2fa2015-07-31 06:48:27 -070084bool GrAADistanceFieldPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
jvanverthfb1e2fc2015-09-15 13:11:11 -070085
jvanverthfa38a302014-10-06 05:59:05 -070086 // TODO: Support inverse fill
robertphillipse7d4b2f2015-08-13 07:57:10 -070087 if (!args.fShaderCaps->shaderDerivativeSupport() || !args.fAntiAlias ||
jvanverth512e4372015-11-23 11:50:02 -080088 SkStrokeRec::kHairline_Style == args.fStroke->getStyle() ||
89 args.fPath->isInverseFillType() || args.fPath->isVolatile()) {
jvanverthfa38a302014-10-06 05:59:05 -070090 return false;
91 }
92
jvanverthb61283f2014-10-30 05:57:21 -070093 // currently don't support perspective
bsalomon0aff2fa2015-07-31 06:48:27 -070094 if (args.fViewMatrix->hasPerspective()) {
jvanverthfa38a302014-10-06 05:59:05 -070095 return false;
96 }
97
jvanverth512e4372015-11-23 11:50:02 -080098 // only support paths with bounds within kMediumMIP by kMediumMIP,
99 // scaled to have bounds within 2.0f*kLargeMIP by 2.0f*kLargeMIP
jvanverthb61283f2014-10-30 05:57:21 -0700100 // the goal is to accelerate rendering of lots of small paths that may be scaling
bsalomon0aff2fa2015-07-31 06:48:27 -0700101 SkScalar maxScale = args.fViewMatrix->getMaxScale();
102 const SkRect& bounds = args.fPath->getBounds();
jvanverthb61283f2014-10-30 05:57:21 -0700103 SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height());
jvanverth512e4372015-11-23 11:50:02 -0800104 // Approximate stroked size by adding the maximum of the stroke width or 2x the miter limit
105 if (!args.fStroke->isFillStyle()) {
106 SkScalar extraWidth = args.fStroke->getWidth();
107 if (SkPaint::kMiter_Join == args.fStroke->getJoin()) {
108 extraWidth = SkTMax(extraWidth, 2.0f*args.fStroke->getMiter());
109 }
110 maxDim += extraWidth;
111 }
112
113 return maxDim <= kMediumMIP && maxDim * maxScale <= 2.0f*kLargeMIP;
jvanverthfa38a302014-10-06 05:59:05 -0700114}
115
jvanverthfa38a302014-10-06 05:59:05 -0700116////////////////////////////////////////////////////////////////////////////////
117
joshualitt5bf99f12015-03-13 11:47:42 -0700118// padding around path bounds to allow for antialiased pixels
119static const SkScalar kAntiAliasPad = 1.0f;
120
bsalomonabd30f52015-08-13 13:34:48 -0700121class AADistanceFieldPathBatch : public GrVertexBatch {
joshualitt5bf99f12015-03-13 11:47:42 -0700122public:
reed1b55a962015-09-17 20:16:13 -0700123 DEFINE_BATCH_CLASS_ID
124
joshualitt5bf99f12015-03-13 11:47:42 -0700125 typedef GrAADistanceFieldPathRenderer::PathData PathData;
126 typedef SkTDynamicHash<PathData, PathData::Key> PathCache;
127 typedef GrAADistanceFieldPathRenderer::PathDataList PathDataList;
128
129 struct Geometry {
jvanverth512e4372015-11-23 11:50:02 -0800130 Geometry(const SkStrokeRec& stroke) : fStroke(stroke) {
131 if (!stroke.needToApply()) {
132 // purify unused values to ensure binary equality
133 fStroke.setStrokeParams(SkPaint::kDefault_Cap, SkPaint::kDefault_Join,
134 SkIntToScalar(4));
135 if (fStroke.getWidth() < 0) {
136 fStroke.setStrokeStyle(-1.0f);
137 }
138 }
139 }
joshualitt5bf99f12015-03-13 11:47:42 -0700140 SkPath fPath;
jvanverth512e4372015-11-23 11:50:02 -0800141 // The unique ID of the path involved in this draw. This may be different than the ID
142 // in fPath since that path may have resulted from a SkStrokeRec::applyToPath call.
143 uint32_t fGenID;
joshualitt5bf99f12015-03-13 11:47:42 -0700144 SkStrokeRec fStroke;
joshualitt53f26aa2015-12-10 07:29:54 -0800145 GrColor fColor;
joshualitt5bf99f12015-03-13 11:47:42 -0700146 bool fAntiAlias;
joshualitt5bf99f12015-03-13 11:47:42 -0700147 };
148
joshualitt53f26aa2015-12-10 07:29:54 -0800149 static GrDrawBatch* Create(const Geometry& geometry, const SkMatrix& viewMatrix,
bsalomonabd30f52015-08-13 13:34:48 -0700150 GrBatchAtlas* atlas, PathCache* pathCache, PathDataList* pathList) {
joshualitt53f26aa2015-12-10 07:29:54 -0800151 return new AADistanceFieldPathBatch(geometry, viewMatrix, atlas, pathCache, pathList);
joshualitt5bf99f12015-03-13 11:47:42 -0700152 }
153
mtklein36352bf2015-03-25 18:17:31 -0700154 const char* name() const override { return "AADistanceFieldPathBatch"; }
joshualitt5bf99f12015-03-13 11:47:42 -0700155
ethannicholasff210322015-11-24 12:10:10 -0800156 void computePipelineOptimizations(GrInitInvariantOutput* color,
157 GrInitInvariantOutput* coverage,
158 GrBatchToXPOverrides* overrides) const override {
joshualitt53f26aa2015-12-10 07:29:54 -0800159 color->setKnownFourComponents(fGeoData[0].fColor);
ethannicholasff210322015-11-24 12:10:10 -0800160 coverage->setUnknownSingleComponent();
161 overrides->fUsePLSDstRead = false;
joshualitt5bf99f12015-03-13 11:47:42 -0700162 }
163
bsalomone46f9fe2015-08-18 06:05:14 -0700164private:
ethannicholasff210322015-11-24 12:10:10 -0800165 void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
joshualitt5bf99f12015-03-13 11:47:42 -0700166 // Handle any color overrides
ethannicholasff210322015-11-24 12:10:10 -0800167 if (!overrides.readsColor()) {
joshualitt53f26aa2015-12-10 07:29:54 -0800168 fGeoData[0].fColor = GrColor_ILLEGAL;
joshualitt5bf99f12015-03-13 11:47:42 -0700169 }
joshualitt53f26aa2015-12-10 07:29:54 -0800170 overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
joshualitt5bf99f12015-03-13 11:47:42 -0700171
172 // setup batch properties
ethannicholasff210322015-11-24 12:10:10 -0800173 fBatch.fColorIgnored = !overrides.readsColor();
174 fBatch.fUsesLocalCoords = overrides.readsLocalCoords();
175 fBatch.fCoverageIgnored = !overrides.readsCoverage();
joshualitt5bf99f12015-03-13 11:47:42 -0700176 }
177
bsalomonb5238a72015-05-05 07:49:49 -0700178 struct FlushInfo {
179 SkAutoTUnref<const GrVertexBuffer> fVertexBuffer;
180 SkAutoTUnref<const GrIndexBuffer> fIndexBuffer;
181 int fVertexOffset;
182 int fInstancesToFlush;
183 };
184
joshualitt144c3c82015-11-30 12:30:13 -0800185 void onPrepareDraws(Target* target) const override {
joshualitt5bf99f12015-03-13 11:47:42 -0700186 int instanceCount = fGeoData.count();
187
188 SkMatrix invert;
189 if (this->usesLocalCoords() && !this->viewMatrix().invert(&invert)) {
190 SkDebugf("Could not invert viewmatrix\n");
191 return;
192 }
193
194 uint32_t flags = 0;
195 flags |= this->viewMatrix().isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
196
197 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_FilterMode);
198
199 // Setup GrGeometryProcessor
200 GrBatchAtlas* atlas = fAtlas;
201 SkAutoTUnref<GrGeometryProcessor> dfProcessor(
jvanverth502286d2015-04-08 12:37:51 -0700202 GrDistanceFieldPathGeoProc::Create(this->color(),
203 this->viewMatrix(),
204 atlas->getTexture(),
205 params,
joshualittb8c241a2015-05-19 08:23:30 -0700206 flags,
207 this->usesLocalCoords()));
joshualitt5bf99f12015-03-13 11:47:42 -0700208
bsalomon75398562015-08-17 12:55:38 -0700209 target->initDraw(dfProcessor, this->pipeline());
joshualitt5bf99f12015-03-13 11:47:42 -0700210
bsalomonb5238a72015-05-05 07:49:49 -0700211 FlushInfo flushInfo;
bsalomoned0bcad2015-05-04 10:36:42 -0700212
joshualitt5bf99f12015-03-13 11:47:42 -0700213 // allocate vertices
214 size_t vertexStride = dfProcessor->getVertexStride();
joshualitt53f26aa2015-12-10 07:29:54 -0800215 SkASSERT(vertexStride == 2 * sizeof(SkPoint) + sizeof(GrColor));
bsalomonb5238a72015-05-05 07:49:49 -0700216
joshualitt5bf99f12015-03-13 11:47:42 -0700217 const GrVertexBuffer* vertexBuffer;
bsalomon75398562015-08-17 12:55:38 -0700218 void* vertices = target->makeVertexSpace(vertexStride,
219 kVerticesPerQuad * instanceCount,
220 &vertexBuffer,
221 &flushInfo.fVertexOffset);
bsalomonb5238a72015-05-05 07:49:49 -0700222 flushInfo.fVertexBuffer.reset(SkRef(vertexBuffer));
bsalomon75398562015-08-17 12:55:38 -0700223 flushInfo.fIndexBuffer.reset(target->resourceProvider()->refQuadIndexBuffer());
bsalomonb5238a72015-05-05 07:49:49 -0700224 if (!vertices || !flushInfo.fIndexBuffer) {
joshualitt5bf99f12015-03-13 11:47:42 -0700225 SkDebugf("Could not allocate vertices\n");
226 return;
227 }
228
bsalomonb5238a72015-05-05 07:49:49 -0700229 flushInfo.fInstancesToFlush = 0;
joshualitt5bf99f12015-03-13 11:47:42 -0700230 for (int i = 0; i < instanceCount; i++) {
joshualitt144c3c82015-11-30 12:30:13 -0800231 const Geometry& args = fGeoData[i];
joshualitt5bf99f12015-03-13 11:47:42 -0700232
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
jvanverth512e4372015-11-23 11:50:02 -0800248 PathData::Key key(args.fGenID, desiredDimension, args.fStroke);
joshualitt144c3c82015-11-30 12:30:13 -0800249 PathData* pathData = fPathCache->find(key);
250 if (nullptr == pathData || !atlas->hasID(pathData->fID)) {
joshualitt5bf99f12015-03-13 11:47:42 -0700251 // Remove the stale cache entry
joshualitt144c3c82015-11-30 12:30:13 -0800252 if (pathData) {
253 fPathCache->remove(pathData->fKey);
254 fPathList->remove(pathData);
255 delete pathData;
joshualitt5bf99f12015-03-13 11:47:42 -0700256 }
257 SkScalar scale = desiredDimension/maxDim;
joshualitt144c3c82015-11-30 12:30:13 -0800258 pathData = new PathData;
bsalomon75398562015-08-17 12:55:38 -0700259 if (!this->addPathToAtlas(target,
joshualitt5bf99f12015-03-13 11:47:42 -0700260 dfProcessor,
bsalomonfb1141a2015-08-06 08:52:49 -0700261 this->pipeline(),
bsalomonb5238a72015-05-05 07:49:49 -0700262 &flushInfo,
joshualitt5bf99f12015-03-13 11:47:42 -0700263 atlas,
joshualitt144c3c82015-11-30 12:30:13 -0800264 pathData,
joshualitt5bf99f12015-03-13 11:47:42 -0700265 args.fPath,
jvanverth512e4372015-11-23 11:50:02 -0800266 args.fGenID,
joshualitt5bf99f12015-03-13 11:47:42 -0700267 args.fStroke,
268 args.fAntiAlias,
269 desiredDimension,
270 scale)) {
271 SkDebugf("Can't rasterize path\n");
272 return;
273 }
274 }
275
joshualitt144c3c82015-11-30 12:30:13 -0800276 atlas->setLastUseToken(pathData->fID, target->currentToken());
joshualitt5bf99f12015-03-13 11:47:42 -0700277
278 // Now set vertices
279 intptr_t offset = reinterpret_cast<intptr_t>(vertices);
bsalomonb5238a72015-05-05 07:49:49 -0700280 offset += i * kVerticesPerQuad * vertexStride;
bsalomon75398562015-08-17 12:55:38 -0700281 this->writePathVertices(target,
bsalomonb5238a72015-05-05 07:49:49 -0700282 atlas,
bsalomonfb1141a2015-08-06 08:52:49 -0700283 this->pipeline(),
bsalomonb5238a72015-05-05 07:49:49 -0700284 dfProcessor,
joshualitt53f26aa2015-12-10 07:29:54 -0800285 offset,
286 args.fColor,
bsalomonb5238a72015-05-05 07:49:49 -0700287 vertexStride,
288 this->viewMatrix(),
289 args.fPath,
joshualitt144c3c82015-11-30 12:30:13 -0800290 pathData);
bsalomonb5238a72015-05-05 07:49:49 -0700291 flushInfo.fInstancesToFlush++;
joshualitt5bf99f12015-03-13 11:47:42 -0700292 }
293
bsalomon75398562015-08-17 12:55:38 -0700294 this->flush(target, &flushInfo);
joshualitt5bf99f12015-03-13 11:47:42 -0700295 }
296
297 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
298
joshualitt53f26aa2015-12-10 07:29:54 -0800299 AADistanceFieldPathBatch(const Geometry& geometry,
300 const SkMatrix& viewMatrix,
joshualitt5bf99f12015-03-13 11:47:42 -0700301 GrBatchAtlas* atlas,
reed1b55a962015-09-17 20:16:13 -0700302 PathCache* pathCache, PathDataList* pathList)
303 : INHERITED(ClassID()) {
joshualitt5bf99f12015-03-13 11:47:42 -0700304 fBatch.fViewMatrix = viewMatrix;
305 fGeoData.push_back(geometry);
joshualitt5bf99f12015-03-13 11:47:42 -0700306
307 fAtlas = atlas;
308 fPathCache = pathCache;
309 fPathList = pathList;
joshualitt99c7c072015-05-01 13:43:30 -0700310
311 // Compute bounds
312 fBounds = geometry.fPath.getBounds();
313 viewMatrix.mapRect(&fBounds);
joshualitt5bf99f12015-03-13 11:47:42 -0700314 }
315
bsalomon75398562015-08-17 12:55:38 -0700316 bool addPathToAtlas(GrVertexBatch::Target* target,
joshualitt5bf99f12015-03-13 11:47:42 -0700317 const GrGeometryProcessor* dfProcessor,
318 const GrPipeline* pipeline,
bsalomonb5238a72015-05-05 07:49:49 -0700319 FlushInfo* flushInfo,
joshualitt5bf99f12015-03-13 11:47:42 -0700320 GrBatchAtlas* atlas,
321 PathData* pathData,
322 const SkPath& path,
jvanverth512e4372015-11-23 11:50:02 -0800323 uint32_t genID,
324 const SkStrokeRec& stroke,
325 bool antiAlias,
joshualitt5bf99f12015-03-13 11:47:42 -0700326 uint32_t dimension,
joshualitt144c3c82015-11-30 12:30:13 -0800327 SkScalar scale) const {
joshualitt5bf99f12015-03-13 11:47:42 -0700328 const SkRect& bounds = path.getBounds();
329
330 // generate bounding rect for bitmap draw
331 SkRect scaledBounds = bounds;
332 // scale to mip level size
333 scaledBounds.fLeft *= scale;
334 scaledBounds.fTop *= scale;
335 scaledBounds.fRight *= scale;
336 scaledBounds.fBottom *= scale;
337 // move the origin to an integer boundary (gives better results)
338 SkScalar dx = SkScalarFraction(scaledBounds.fLeft);
339 SkScalar dy = SkScalarFraction(scaledBounds.fTop);
340 scaledBounds.offset(-dx, -dy);
341 // get integer boundary
342 SkIRect devPathBounds;
343 scaledBounds.roundOut(&devPathBounds);
344 // pad to allow room for antialiasing
jvanverthecbed9d2015-12-18 10:07:52 -0800345 const int intPad = SkScalarCeilToInt(kAntiAliasPad);
346 // pre-move origin (after outset, will be 0,0)
347 int width = devPathBounds.width();
348 int height = devPathBounds.height();
349 devPathBounds.fLeft = intPad;
350 devPathBounds.fTop = intPad;
351 devPathBounds.fRight = intPad + width;
352 devPathBounds.fBottom = intPad + height;
353 devPathBounds.outset(intPad, intPad);
joshualitt5bf99f12015-03-13 11:47:42 -0700354
355 // draw path to bitmap
356 SkMatrix drawMatrix;
357 drawMatrix.setTranslate(-bounds.left(), -bounds.top());
358 drawMatrix.postScale(scale, scale);
359 drawMatrix.postTranslate(kAntiAliasPad, kAntiAliasPad);
360
361 // setup bitmap backing
jvanverth512e4372015-11-23 11:50:02 -0800362 SkASSERT(devPathBounds.fLeft == 0);
363 SkASSERT(devPathBounds.fTop == 0);
reed41e010c2015-06-09 12:16:53 -0700364 SkAutoPixmapStorage dst;
jvanverth512e4372015-11-23 11:50:02 -0800365 if (!dst.tryAlloc(SkImageInfo::MakeA8(devPathBounds.width(),
366 devPathBounds.height()))) {
joshualitt5bf99f12015-03-13 11:47:42 -0700367 return false;
368 }
reed41e010c2015-06-09 12:16:53 -0700369 sk_bzero(dst.writable_addr(), dst.getSafeSize());
joshualitt5bf99f12015-03-13 11:47:42 -0700370
371 // rasterize path
372 SkPaint paint;
jvanverth512e4372015-11-23 11:50:02 -0800373 paint.setStyle(SkPaint::kFill_Style);
joshualitt5bf99f12015-03-13 11:47:42 -0700374 paint.setAntiAlias(antiAlias);
375
376 SkDraw draw;
377 sk_bzero(&draw, sizeof(draw));
378
379 SkRasterClip rasterClip;
jvanverth512e4372015-11-23 11:50:02 -0800380 rasterClip.setRect(devPathBounds);
joshualitt5bf99f12015-03-13 11:47:42 -0700381 draw.fRC = &rasterClip;
382 draw.fClip = &rasterClip.bwRgn();
383 draw.fMatrix = &drawMatrix;
reed41e010c2015-06-09 12:16:53 -0700384 draw.fDst = dst;
joshualitt5bf99f12015-03-13 11:47:42 -0700385
386 draw.drawPathCoverage(path, paint);
387
388 // generate signed distance field
389 devPathBounds.outset(SK_DistanceFieldPad, SK_DistanceFieldPad);
jvanverthecbed9d2015-12-18 10:07:52 -0800390 width = devPathBounds.width();
391 height = devPathBounds.height();
joshualitt5bf99f12015-03-13 11:47:42 -0700392 // TODO We should really generate this directly into the plot somehow
393 SkAutoSMalloc<1024> dfStorage(width * height * sizeof(unsigned char));
394
395 // Generate signed distance field
reed41e010c2015-06-09 12:16:53 -0700396 SkGenerateDistanceFieldFromA8Image((unsigned char*)dfStorage.get(),
397 (const unsigned char*)dst.addr(),
398 dst.width(), dst.height(), dst.rowBytes());
joshualitt5bf99f12015-03-13 11:47:42 -0700399
400 // add to atlas
401 SkIPoint16 atlasLocation;
402 GrBatchAtlas::AtlasID id;
bsalomon75398562015-08-17 12:55:38 -0700403 bool success = atlas->addToAtlas(&id, target, width, height, dfStorage.get(),
joshualitt5bf99f12015-03-13 11:47:42 -0700404 &atlasLocation);
405 if (!success) {
bsalomon75398562015-08-17 12:55:38 -0700406 this->flush(target, flushInfo);
407 target->initDraw(dfProcessor, pipeline);
joshualitt5bf99f12015-03-13 11:47:42 -0700408
bsalomon75398562015-08-17 12:55:38 -0700409 SkDEBUGCODE(success =) atlas->addToAtlas(&id, target, width, height,
joshualitt5bf99f12015-03-13 11:47:42 -0700410 dfStorage.get(), &atlasLocation);
411 SkASSERT(success);
412
413 }
414
415 // add to cache
jvanverth512e4372015-11-23 11:50:02 -0800416 pathData->fKey = PathData::Key(genID, dimension, stroke);
joshualitt5bf99f12015-03-13 11:47:42 -0700417 pathData->fScale = scale;
418 pathData->fID = id;
419 // change the scaled rect to match the size of the inset distance field
420 scaledBounds.fRight = scaledBounds.fLeft +
421 SkIntToScalar(devPathBounds.width() - 2*SK_DistanceFieldInset);
422 scaledBounds.fBottom = scaledBounds.fTop +
423 SkIntToScalar(devPathBounds.height() - 2*SK_DistanceFieldInset);
424 // shift the origin to the correct place relative to the distance field
425 // need to also restore the fractional translation
426 scaledBounds.offset(-SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPad + dx,
427 -SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPad + dy);
428 pathData->fBounds = scaledBounds;
429 // origin we render from is inset from distance field edge
430 atlasLocation.fX += SK_DistanceFieldInset;
431 atlasLocation.fY += SK_DistanceFieldInset;
432 pathData->fAtlasLocation = atlasLocation;
433
434 fPathCache->add(pathData);
435 fPathList->addToTail(pathData);
436#ifdef DF_PATH_TRACKING
437 ++g_NumCachedPaths;
438#endif
439 return true;
440 }
441
bsalomon75398562015-08-17 12:55:38 -0700442 void writePathVertices(GrDrawBatch::Target* target,
bsalomonb5238a72015-05-05 07:49:49 -0700443 GrBatchAtlas* atlas,
444 const GrPipeline* pipeline,
445 const GrGeometryProcessor* gp,
joshualitt53f26aa2015-12-10 07:29:54 -0800446 intptr_t offset,
447 GrColor color,
bsalomonb5238a72015-05-05 07:49:49 -0700448 size_t vertexStride,
449 const SkMatrix& viewMatrix,
450 const SkPath& path,
joshualitt144c3c82015-11-30 12:30:13 -0800451 const PathData* pathData) const {
joshualitt5bf99f12015-03-13 11:47:42 -0700452 GrTexture* texture = atlas->getTexture();
453
454 SkScalar dx = pathData->fBounds.fLeft;
455 SkScalar dy = pathData->fBounds.fTop;
456 SkScalar width = pathData->fBounds.width();
457 SkScalar height = pathData->fBounds.height();
458
459 SkScalar invScale = 1.0f / pathData->fScale;
460 dx *= invScale;
461 dy *= invScale;
462 width *= invScale;
463 height *= invScale;
464
465 SkFixed tx = SkIntToFixed(pathData->fAtlasLocation.fX);
466 SkFixed ty = SkIntToFixed(pathData->fAtlasLocation.fY);
467 SkFixed tw = SkScalarToFixed(pathData->fBounds.width());
468 SkFixed th = SkScalarToFixed(pathData->fBounds.height());
469
joshualitt53f26aa2015-12-10 07:29:54 -0800470 SkPoint* positions = reinterpret_cast<SkPoint*>(offset);
471
joshualitt5bf99f12015-03-13 11:47:42 -0700472 // vertex positions
473 // TODO make the vertex attributes a struct
474 SkRect r = SkRect::MakeXYWH(dx, dy, width, height);
475 positions->setRectFan(r.left(), r.top(), r.right(), r.bottom(), vertexStride);
476
joshualitt53f26aa2015-12-10 07:29:54 -0800477 // colors
478 for (int i = 0; i < kVerticesPerQuad; i++) {
479 GrColor* colorPtr = (GrColor*)(offset + sizeof(SkPoint) + i * vertexStride);
480 *colorPtr = color;
481 }
482
joshualitt5bf99f12015-03-13 11:47:42 -0700483 // vertex texture coords
joshualitt53f26aa2015-12-10 07:29:54 -0800484 SkPoint* textureCoords = (SkPoint*)(offset + sizeof(SkPoint) + sizeof(GrColor));
joshualitt5bf99f12015-03-13 11:47:42 -0700485 textureCoords->setRectFan(SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx)),
486 SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty)),
487 SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx + tw)),
488 SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty + th)),
489 vertexStride);
490 }
491
joshualitt144c3c82015-11-30 12:30:13 -0800492 void flush(GrVertexBatch::Target* target, FlushInfo* flushInfo) const {
bsalomoncb8979d2015-05-05 09:51:38 -0700493 GrVertices vertices;
bsalomonb5238a72015-05-05 07:49:49 -0700494 int maxInstancesPerDraw = flushInfo->fIndexBuffer->maxQuads();
bsalomoncb8979d2015-05-05 09:51:38 -0700495 vertices.initInstanced(kTriangles_GrPrimitiveType, flushInfo->fVertexBuffer,
bsalomonb5238a72015-05-05 07:49:49 -0700496 flushInfo->fIndexBuffer, flushInfo->fVertexOffset, kVerticesPerQuad,
bsalomone64eb572015-05-07 11:35:55 -0700497 kIndicesPerQuad, flushInfo->fInstancesToFlush, maxInstancesPerDraw);
bsalomon75398562015-08-17 12:55:38 -0700498 target->draw(vertices);
bsalomonb5238a72015-05-05 07:49:49 -0700499 flushInfo->fVertexOffset += kVerticesPerQuad * flushInfo->fInstancesToFlush;
500 flushInfo->fInstancesToFlush = 0;
joshualitt5bf99f12015-03-13 11:47:42 -0700501 }
502
joshualitt53f26aa2015-12-10 07:29:54 -0800503 GrColor color() const { return fGeoData[0].fColor; }
joshualitt5bf99f12015-03-13 11:47:42 -0700504 const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; }
505 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
506
bsalomoncb02b382015-08-12 11:14:50 -0700507 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
bsalomonabd30f52015-08-13 13:34:48 -0700508 AADistanceFieldPathBatch* that = t->cast<AADistanceFieldPathBatch>();
509 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
510 that->bounds(), caps)) {
joshualitt8cab9a72015-07-16 09:13:50 -0700511 return false;
512 }
513
joshualitt53f26aa2015-12-10 07:29:54 -0800514 // TODO We can position on the cpu
joshualitt5bf99f12015-03-13 11:47:42 -0700515 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
516 return false;
517 }
518
519 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
joshualitt99c7c072015-05-01 13:43:30 -0700520 this->joinBounds(that->bounds());
joshualitt5bf99f12015-03-13 11:47:42 -0700521 return true;
522 }
523
524 struct BatchTracker {
joshualitt5bf99f12015-03-13 11:47:42 -0700525 SkMatrix fViewMatrix;
526 bool fUsesLocalCoords;
527 bool fColorIgnored;
528 bool fCoverageIgnored;
529 };
530
531 BatchTracker fBatch;
532 SkSTArray<1, Geometry, true> fGeoData;
533 GrBatchAtlas* fAtlas;
534 PathCache* fPathCache;
535 PathDataList* fPathList;
reed1b55a962015-09-17 20:16:13 -0700536
537 typedef GrVertexBatch INHERITED;
joshualitt5bf99f12015-03-13 11:47:42 -0700538};
539
bsalomon0aff2fa2015-07-31 06:48:27 -0700540bool GrAADistanceFieldPathRenderer::onDrawPath(const DrawPathArgs& args) {
joshualittde83b412016-01-14 09:58:36 -0800541 GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(),
542 "GrAADistanceFieldPathRenderer::onDrawPath");
jvanverthfa38a302014-10-06 05:59:05 -0700543 // we've already bailed on inverse filled paths, so this is safe
bsalomon0aff2fa2015-07-31 06:48:27 -0700544 if (args.fPath->isEmpty()) {
jvanverthfa38a302014-10-06 05:59:05 -0700545 return true;
546 }
547
joshualitt5bf99f12015-03-13 11:47:42 -0700548 if (!fAtlas) {
joshualittb356cbc2015-08-05 06:36:39 -0700549 fAtlas = args.fResourceProvider->createAtlas(kAlpha_8_GrPixelConfig,
550 ATLAS_TEXTURE_WIDTH, ATLAS_TEXTURE_HEIGHT,
551 NUM_PLOTS_X, NUM_PLOTS_Y,
552 &GrAADistanceFieldPathRenderer::HandleEviction,
553 (void*)this);
joshualitt21279c72015-05-11 07:21:37 -0700554 if (!fAtlas) {
jvanverthfa38a302014-10-06 05:59:05 -0700555 return false;
556 }
557 }
558
bsalomon0aff2fa2015-07-31 06:48:27 -0700559 AADistanceFieldPathBatch::Geometry geometry(*args.fStroke);
jvanverth512e4372015-11-23 11:50:02 -0800560 if (SkStrokeRec::kFill_Style == args.fStroke->getStyle()) {
561 geometry.fPath = *args.fPath;
562 } else {
563 args.fStroke->applyToPath(&geometry.fPath, *args.fPath);
564 }
joshualitt53f26aa2015-12-10 07:29:54 -0800565 geometry.fColor = args.fColor;
bsalomon0aff2fa2015-07-31 06:48:27 -0700566 geometry.fAntiAlias = args.fAntiAlias;
jvanverth512e4372015-11-23 11:50:02 -0800567 // Note: this is the generation ID of the _original_ path. When a new path is
568 // generated due to stroking it is important that the original path's id is used
569 // for caching.
570 geometry.fGenID = args.fPath->getGenerationID();
571
joshualitt53f26aa2015-12-10 07:29:54 -0800572 SkAutoTUnref<GrDrawBatch> batch(AADistanceFieldPathBatch::Create(geometry,
bsalomonabd30f52015-08-13 13:34:48 -0700573 *args.fViewMatrix, fAtlas,
574 &fPathCache, &fPathList));
bsalomon0aff2fa2015-07-31 06:48:27 -0700575 args.fTarget->drawBatch(*args.fPipelineBuilder, batch);
joshualitt9491f7f2015-02-11 11:33:38 -0800576
jvanverthfa38a302014-10-06 05:59:05 -0700577 return true;
578}
579
joshualitt21279c72015-05-11 07:21:37 -0700580///////////////////////////////////////////////////////////////////////////////////////////////////
581
582#ifdef GR_TEST_UTILS
583
584struct PathTestStruct {
585 typedef GrAADistanceFieldPathRenderer::PathCache PathCache;
586 typedef GrAADistanceFieldPathRenderer::PathData PathData;
587 typedef GrAADistanceFieldPathRenderer::PathDataList PathDataList;
halcanary96fcdcc2015-08-27 07:41:13 -0700588 PathTestStruct() : fContextID(SK_InvalidGenID), fAtlas(nullptr) {}
joshualitt21279c72015-05-11 07:21:37 -0700589 ~PathTestStruct() { this->reset(); }
590
591 void reset() {
592 PathDataList::Iter iter;
593 iter.init(fPathList, PathDataList::Iter::kHead_IterStart);
594 PathData* pathData;
595 while ((pathData = iter.get())) {
596 iter.next();
597 fPathList.remove(pathData);
halcanary385fe4d2015-08-26 13:07:48 -0700598 delete pathData;
joshualitt21279c72015-05-11 07:21:37 -0700599 }
halcanary385fe4d2015-08-26 13:07:48 -0700600 delete fAtlas;
joshualitt6c891102015-05-13 08:51:49 -0700601 fPathCache.reset();
joshualitt21279c72015-05-11 07:21:37 -0700602 }
603
604 static void HandleEviction(GrBatchAtlas::AtlasID id, void* pr) {
605 PathTestStruct* dfpr = (PathTestStruct*)pr;
606 // remove any paths that use this plot
607 PathDataList::Iter iter;
608 iter.init(dfpr->fPathList, PathDataList::Iter::kHead_IterStart);
609 PathData* pathData;
610 while ((pathData = iter.get())) {
611 iter.next();
612 if (id == pathData->fID) {
613 dfpr->fPathCache.remove(pathData->fKey);
614 dfpr->fPathList.remove(pathData);
halcanary385fe4d2015-08-26 13:07:48 -0700615 delete pathData;
joshualitt21279c72015-05-11 07:21:37 -0700616 }
617 }
618 }
619
620 uint32_t fContextID;
621 GrBatchAtlas* fAtlas;
622 PathCache fPathCache;
623 PathDataList fPathList;
624};
625
bsalomonabd30f52015-08-13 13:34:48 -0700626DRAW_BATCH_TEST_DEFINE(AADistanceFieldPathBatch) {
joshualitt21279c72015-05-11 07:21:37 -0700627 static PathTestStruct gTestStruct;
628
629 if (context->uniqueID() != gTestStruct.fContextID) {
630 gTestStruct.fContextID = context->uniqueID();
631 gTestStruct.reset();
joshualittb356cbc2015-08-05 06:36:39 -0700632 gTestStruct.fAtlas =
633 context->resourceProvider()->createAtlas(kAlpha_8_GrPixelConfig,
634 ATLAS_TEXTURE_WIDTH, ATLAS_TEXTURE_HEIGHT,
635 NUM_PLOTS_X, NUM_PLOTS_Y,
636 &PathTestStruct::HandleEviction,
637 (void*)&gTestStruct);
joshualitt21279c72015-05-11 07:21:37 -0700638 }
639
640 SkMatrix viewMatrix = GrTest::TestMatrix(random);
641 GrColor color = GrRandomColor(random);
642
643 AADistanceFieldPathBatch::Geometry geometry(GrTest::TestStrokeRec(random));
joshualitt53f26aa2015-12-10 07:29:54 -0800644 geometry.fColor = color;
joshualitt21279c72015-05-11 07:21:37 -0700645 geometry.fPath = GrTest::TestPath(random);
646 geometry.fAntiAlias = random->nextBool();
jvanverth512e4372015-11-23 11:50:02 -0800647 geometry.fGenID = random->nextU();
joshualitt21279c72015-05-11 07:21:37 -0700648
joshualitt53f26aa2015-12-10 07:29:54 -0800649 return AADistanceFieldPathBatch::Create(geometry, viewMatrix,
joshualitt21279c72015-05-11 07:21:37 -0700650 gTestStruct.fAtlas,
651 &gTestStruct.fPathCache,
652 &gTestStruct.fPathList);
653}
654
655#endif