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

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

Issue 589103004: Add GrAASmallPathRenderer. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Address nits Created 6 years, 2 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/GrAddPathRenderers_default.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1
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
11 #include "GrAtlas.h"
12 #include "GrContext.h"
13 #include "GrDrawState.h"
14 #include "GrSurfacePriv.h"
15 #include "GrSWMaskHelper.h"
16 #include "GrTexturePriv.h"
17 #include "effects/GrDistanceFieldTextureEffect.h"
18
19 #include "SkDistanceFieldGen.h"
20 #include "SkRTConf.h"
21
22 #define ATLAS_TEXTURE_WIDTH 1024
23 #define ATLAS_TEXTURE_HEIGHT 1024
24
25 #define PLOT_WIDTH 256
26 #define PLOT_HEIGHT 256
27
28 #define NUM_PLOTS_X (ATLAS_TEXTURE_WIDTH / PLOT_WIDTH)
29 #define NUM_PLOTS_Y (ATLAS_TEXTURE_HEIGHT / PLOT_HEIGHT)
30
31 SK_CONF_DECLARE(bool, c_DumpPathCache, "gpu.dumpPathCache", false,
32 "Dump the contents of the path cache before every purge.");
33
34 ////////////////////////////////////////////////////////////////////////////////
35 GrAADistanceFieldPathRenderer::~GrAADistanceFieldPathRenderer() {
36 PathDataList::Iter iter;
37 iter.init(fPathList, PathDataList::Iter::kHead_IterStart);
38 PathData* pathData;
39 while ((pathData = iter.get())) {
40 iter.next();
41 fPathList.remove(pathData);
42 SkDELETE(pathData);
43 }
44
45 SkDELETE(fAtlas);
46 }
47
48 ////////////////////////////////////////////////////////////////////////////////
49 bool GrAADistanceFieldPathRenderer::canDrawPath(const SkPath& path,
50 const SkStrokeRec& stroke,
51 const GrDrawTarget* target,
52 bool antiAlias) const {
53 // TODO: Support inverse fill
54 // TODO: Support strokes
55 if (!target->caps()->shaderDerivativeSupport() || !antiAlias || path.isInver seFillType()
56 || SkStrokeRec::kFill_Style != stroke.getStyle()) {
57 return false;
58 }
59
60 // currently don't support perspective or scaling more than 3x
61 const GrDrawState& drawState = target->getDrawState();
62 const SkMatrix& vm = drawState.getViewMatrix();
63 if (vm.hasPerspective() || vm.getMaxScale() > 3.0f) {
64 return false;
65 }
66
67 // only support paths smaller than 64 x 64
68 const SkRect& bounds = path.getBounds();
69 return bounds.width() < 64.f && bounds.height() < 64.f;
70 }
71
72
73 GrPathRenderer::StencilSupport GrAADistanceFieldPathRenderer::onGetStencilSuppor t(
74 const SkP ath&,
75 const SkS trokeRec&,
76 const GrD rawTarget*) const {
77 return GrPathRenderer::kNoSupport_StencilSupport;
78 }
79
80 ////////////////////////////////////////////////////////////////////////////////
81
82 // position + texture coord
83 extern const GrVertexAttrib gSDFPathVertexAttribs[] = {
84 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
85 { kVec2f_GrVertexAttribType, sizeof(SkPoint), kGeometryProcessor_GrVertexAtt ribBinding }
86 };
87 static const size_t kSDFPathVASize = 2 * sizeof(SkPoint);
88
89 bool GrAADistanceFieldPathRenderer::onDrawPath(const SkPath& path,
90 const SkStrokeRec& stroke,
91 GrDrawTarget* target,
92 bool antiAlias) {
93 // we've already bailed on inverse filled paths, so this is safe
94 if (path.isEmpty()) {
95 return true;
96 }
97
98 SkASSERT(fContext);
99
100 // check to see if path is cached
101 // TODO: handle stroked vs. filled version of same path
102 PathData* pathData = fPathCache.find(path.getGenerationID());
103 if (NULL == pathData) {
104 pathData = this->addPathToAtlas(path, stroke, antiAlias);
105 if (NULL == pathData) {
106 return false;
107 }
108 }
109
110 // use signed distance field to render
111 return this->internalDrawPath(path, pathData, target);
112 }
113
114 // factor used to scale the path prior to building distance field
115 const SkScalar kScaleFactor = 2.0f;
116 // padding around path bounds to allow for antialiased pixels
117 const SkScalar kAntiAliasPad = 1.0f;
118
119 GrAADistanceFieldPathRenderer::PathData* GrAADistanceFieldPathRenderer::addPathT oAtlas(
120 const Sk Path& path,
121 const Sk StrokeRec& stroke,
122 bool ant iAlias) {
123
124 // generate distance field and add to atlas
125 if (NULL == fAtlas) {
126 SkISize textureSize = SkISize::Make(ATLAS_TEXTURE_WIDTH, ATLAS_TEXTURE_H EIGHT);
127 fAtlas = SkNEW_ARGS(GrAtlas, (fContext->getGpu(), kAlpha_8_GrPixelConfig ,
128 kNone_GrTextureFlags, textureSize,
129 NUM_PLOTS_X, NUM_PLOTS_Y, false));
130 if (NULL == fAtlas) {
131 return NULL;
132 }
133 }
134
135 const SkRect& bounds = path.getBounds();
136
137 // generate bounding rect for bitmap draw
138 SkRect scaledBounds = bounds;
139 // scale up to improve maxification range
140 scaledBounds.fLeft *= kScaleFactor;
141 scaledBounds.fTop *= kScaleFactor;
142 scaledBounds.fRight *= kScaleFactor;
143 scaledBounds.fBottom *= kScaleFactor;
144 // move the origin to an integer boundary (gives better results)
145 SkScalar dx = SkScalarFraction(scaledBounds.fLeft);
146 SkScalar dy = SkScalarFraction(scaledBounds.fTop);
147 scaledBounds.offset(-dx, -dy);
148 // get integer boundary
149 SkIRect devPathBounds;
150 scaledBounds.roundOut(&devPathBounds);
151 // pad to allow room for antialiasing
152 devPathBounds.outset(SkScalarCeilToInt(kAntiAliasPad), SkScalarCeilToInt(kAn tiAliasPad));
153 // move origin to upper left corner
154 devPathBounds.offsetTo(0,0);
155
156 // draw path to bitmap
157 SkMatrix drawMatrix;
158 drawMatrix.setTranslate(-bounds.left(), -bounds.top());
159 drawMatrix.postScale(kScaleFactor, kScaleFactor);
160 drawMatrix.postTranslate(kAntiAliasPad, kAntiAliasPad);
161 GrSWMaskHelper helper(fContext);
162
163 if (!helper.init(devPathBounds, &drawMatrix)) {
164 return NULL;
165 }
166 helper.draw(path, stroke, SkRegion::kReplace_Op, antiAlias, 0xFF);
167
168 // generate signed distance field
169 devPathBounds.outset(SK_DistanceFieldPad, SK_DistanceFieldPad);
170 int width = devPathBounds.width();
171 int height = devPathBounds.height();
172 SkAutoSMalloc<1024> dfStorage(width*height*sizeof(unsigned char));
173 helper.toSDF((unsigned char*) dfStorage.get());
174
175 // add to atlas
176 SkIPoint16 atlasLocation;
177 GrPlot* plot = fAtlas->addToAtlas(&fPlotUsage, width, height, dfStorage.get( ),
178 &atlasLocation);
179
180 // if atlas full
181 if (NULL == plot) {
182 if (this->freeUnusedPlot()) {
183 plot = fAtlas->addToAtlas(&fPlotUsage, width, height, dfStorage.get( ),
184 &atlasLocation);
185 if (plot) {
186 goto HAS_ATLAS;
187 }
188 }
189
190 if (c_DumpPathCache) {
191 #ifdef SK_DEVELOPER
192 GrTexture* texture = fAtlas->getTexture();
193 texture->surfacePriv().savePixels("pathcache.png");
194 #endif
195 }
196
197 // before we purge the cache, we must flush any accumulated draws
198 fContext->flush();
199
200 if (this->freeUnusedPlot()) {
201 plot = fAtlas->addToAtlas(&fPlotUsage, width, height, dfStorage.get( ),
202 &atlasLocation);
203 if (plot) {
204 goto HAS_ATLAS;
205 }
206 }
207
208 return NULL;
209 }
210
211 HAS_ATLAS:
212 // add to cache
213 PathData* pathData = SkNEW(PathData);
214 pathData->fGenID = path.getGenerationID();
215 pathData->fPlot = plot;
216 // change the scaled rect to match the size of the inset distance field
217 scaledBounds.fRight = scaledBounds.fLeft +
218 SkIntToScalar(devPathBounds.width() - 2*SK_DistanceFieldInset);
219 scaledBounds.fBottom = scaledBounds.fTop +
220 SkIntToScalar(devPathBounds.height() - 2*SK_DistanceFieldInset);
221 // shift the origin to the correct place relative to the distance field
222 // need to also restore the fractional translation
223 scaledBounds.offset(-SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPad + dx,
224 -SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPad + dy);
225 pathData->fBounds = scaledBounds;
226 // origin we render from is inset from distance field edge
227 atlasLocation.fX += SK_DistanceFieldInset;
228 atlasLocation.fY += SK_DistanceFieldInset;
229 pathData->fAtlasLocation = atlasLocation;
230
231 fPathCache.add(pathData);
232 fPathList.addToTail(pathData);
233
234 return pathData;
235 }
236
237 bool GrAADistanceFieldPathRenderer::freeUnusedPlot() {
238 // find an unused plot
239 GrPlot* plot = fAtlas->getUnusedPlot();
240 if (NULL == plot) {
241 return false;
242 }
243 plot->resetRects();
244
245 // remove any paths that use this plot
246 PathDataList::Iter iter;
247 iter.init(fPathList, PathDataList::Iter::kHead_IterStart);
248 PathData* pathData;
249 while ((pathData = iter.get())) {
250 iter.next();
251 if (plot == pathData->fPlot) {
252 fPathCache.remove(pathData->fGenID);
253 fPathList.remove(pathData);
254 SkDELETE(pathData);
255 }
256 }
257
258 // tell the atlas to free the plot
259 GrAtlas::RemovePlot(&fPlotUsage, plot);
260
261 return true;
262 }
263
264 bool GrAADistanceFieldPathRenderer::internalDrawPath(const SkPath& path,
265 const PathData* pathData,
266 GrDrawTarget* target) {
267
268 GrTexture* texture = fAtlas->getTexture();
269 GrDrawState* drawState = target->drawState();
270
271 SkASSERT(pathData->fPlot);
272 GrDrawTarget::DrawToken drawToken = target->getCurrentDrawToken();
273 pathData->fPlot->setDrawToken(drawToken);
274
275 // make me some vertices
276 drawState->setVertexAttribs<gSDFPathVertexAttribs>(SK_ARRAY_COUNT(gSDFPathVe rtexAttribs),
277 kSDFPathVASize);
278 void* vertices = NULL;
279 void* indices = NULL;
280 bool success = target->reserveVertexAndIndexSpace(4, 6, &vertices, &indices) ;
281 GrAlwaysAssert(success);
282
283 SkScalar dx = pathData->fBounds.fLeft;
284 SkScalar dy = pathData->fBounds.fTop;
285 SkScalar width = pathData->fBounds.width();
286 SkScalar height = pathData->fBounds.height();
287
288 SkScalar invScale = 1.0f/kScaleFactor;
289 dx *= invScale;
290 dy *= invScale;
291 width *= invScale;
292 height *= invScale;
293
294 SkFixed tx = SkIntToFixed(pathData->fAtlasLocation.fX);
295 SkFixed ty = SkIntToFixed(pathData->fAtlasLocation.fY);
296 SkFixed tw = SkScalarToFixed(pathData->fBounds.width());
297 SkFixed th = SkScalarToFixed(pathData->fBounds.height());
298
299 // vertex positions
300 SkRect r = SkRect::MakeXYWH(dx, dy, width, height);
301 size_t vertSize = 2 * sizeof(SkPoint);
302 SkPoint* positions = reinterpret_cast<SkPoint*>(vertices);
303 positions->setRectFan(r.left(), r.top(), r.right(), r.bottom(), vertSize);
304
305 // vertex texture coords
306 intptr_t intPtr = reinterpret_cast<intptr_t>(positions);
307 SkPoint* textureCoords = reinterpret_cast<SkPoint*>(intPtr + vertSize - size of(SkPoint));
308 textureCoords->setRectFan(SkFixedToFloat(texture->texturePriv().normalizeFix edX(tx)),
309 SkFixedToFloat(texture->texturePriv().normalizeFix edY(ty)),
310 SkFixedToFloat(texture->texturePriv().normalizeFix edX(tx + tw)),
311 SkFixedToFloat(texture->texturePriv().normalizeFix edY(ty + th)),
312 vertSize);
313
314 uint16_t* indexPtr = reinterpret_cast<uint16_t*>(indices);
315 *indexPtr++ = 0;
316 *indexPtr++ = 1;
317 *indexPtr++ = 2;
318 *indexPtr++ = 0;
319 *indexPtr++ = 2;
320 *indexPtr++ = 3;
321
322 // set up any flags
323 uint32_t flags = 0;
324 const SkMatrix& vm = drawState->getViewMatrix();
325 flags |= vm.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
326
327 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_ FilterMode);
328 drawState->setGeometryProcessor(GrDistanceFieldNoGammaTextureEffect::Create( texture,
329 params,
330 flags))->unref();
331
332
333 vm.mapRect(&r);
334 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6, &r);
335 target->resetVertexSource();
336 target->resetIndexSource();
337
338 return true;
339 }
340
OLDNEW
« no previous file with comments | « src/gpu/GrAADistanceFieldPathRenderer.h ('k') | src/gpu/GrAddPathRenderers_default.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698