OLD | NEW |
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2014 Google Inc. | 3 * Copyright 2014 Google Inc. |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 | 8 |
9 #include "GrAADistanceFieldPathRenderer.h" | 9 #include "GrAADistanceFieldPathRenderer.h" |
10 | 10 |
11 #include "GrAtlas.h" | 11 #include "GrAtlas.h" |
12 #include "GrContext.h" | 12 #include "GrContext.h" |
13 #include "GrDrawState.h" | 13 #include "GrDrawState.h" |
14 #include "GrSurfacePriv.h" | 14 #include "GrSurfacePriv.h" |
15 #include "GrSWMaskHelper.h" | 15 #include "GrSWMaskHelper.h" |
16 #include "GrTexturePriv.h" | 16 #include "GrTexturePriv.h" |
17 #include "effects/GrDistanceFieldTextureEffect.h" | 17 #include "effects/GrDistanceFieldTextureEffect.h" |
18 | 18 |
19 #include "SkDistanceFieldGen.h" | 19 #include "SkDistanceFieldGen.h" |
20 #include "SkRTConf.h" | 20 #include "SkRTConf.h" |
21 | 21 |
22 #define ATLAS_TEXTURE_WIDTH 1024 | 22 #define ATLAS_TEXTURE_WIDTH 1024 |
23 #define ATLAS_TEXTURE_HEIGHT 1024 | 23 #define ATLAS_TEXTURE_HEIGHT 2048 |
24 #define PLOT_WIDTH 256 | 24 #define PLOT_WIDTH 256 |
25 #define PLOT_HEIGHT 256 | 25 #define PLOT_HEIGHT 256 |
26 | 26 |
27 #define NUM_PLOTS_X (ATLAS_TEXTURE_WIDTH / PLOT_WIDTH) | 27 #define NUM_PLOTS_X (ATLAS_TEXTURE_WIDTH / PLOT_WIDTH) |
28 #define NUM_PLOTS_Y (ATLAS_TEXTURE_HEIGHT / PLOT_HEIGHT) | 28 #define NUM_PLOTS_Y (ATLAS_TEXTURE_HEIGHT / PLOT_HEIGHT) |
29 | 29 |
30 SK_CONF_DECLARE(bool, c_DumpPathCache, "gpu.dumpPathCache", false, | 30 SK_CONF_DECLARE(bool, c_DumpPathCache, "gpu.dumpPathCache", false, |
31 "Dump the contents of the path cache before every purge."); | 31 "Dump the contents of the path cache before every purge."); |
32 | 32 |
33 #ifdef DF_PATH_TRACKING | 33 #ifdef DF_PATH_TRACKING |
34 static int g_NumCachedPaths = 0; | 34 static int g_NumCachedPaths = 0; |
35 static int g_NumFreedPaths = 0; | 35 static int g_NumFreedPaths = 0; |
36 #endif | 36 #endif |
37 | 37 |
| 38 // mip levels |
| 39 static const int kSmallMIP = 32; |
| 40 static const int kMediumMIP = 64; |
| 41 static const int kLargeMIP = 128; |
| 42 |
38 //////////////////////////////////////////////////////////////////////////////// | 43 //////////////////////////////////////////////////////////////////////////////// |
39 GrAADistanceFieldPathRenderer::GrAADistanceFieldPathRenderer(GrContext* context) | 44 GrAADistanceFieldPathRenderer::GrAADistanceFieldPathRenderer(GrContext* context) |
40 : fContext(context) | 45 : fContext(context) |
41 , fAtlas(NULL) | 46 , fAtlas(NULL) |
42 , fEffectFlags(kInvalid_DistanceFieldEffectFlag) { | 47 , fEffectFlags(kInvalid_DistanceFieldEffectFlag) { |
43 } | 48 } |
44 | 49 |
45 GrAADistanceFieldPathRenderer::~GrAADistanceFieldPathRenderer() { | 50 GrAADistanceFieldPathRenderer::~GrAADistanceFieldPathRenderer() { |
46 PathDataList::Iter iter; | 51 PathDataList::Iter iter; |
47 iter.init(fPathList, PathDataList::Iter::kHead_IterStart); | 52 iter.init(fPathList, PathDataList::Iter::kHead_IterStart); |
(...skipping 17 matching lines...) Expand all Loading... |
65 const GrDrawTarget* target, | 70 const GrDrawTarget* target, |
66 bool antiAlias) const { | 71 bool antiAlias) const { |
67 | 72 |
68 // TODO: Support inverse fill | 73 // TODO: Support inverse fill |
69 // TODO: Support strokes | 74 // TODO: Support strokes |
70 if (!target->caps()->shaderDerivativeSupport() || !antiAlias || path.isInver
seFillType() | 75 if (!target->caps()->shaderDerivativeSupport() || !antiAlias || path.isInver
seFillType() |
71 || path.isVolatile() || SkStrokeRec::kFill_Style != stroke.getStyle()) { | 76 || path.isVolatile() || SkStrokeRec::kFill_Style != stroke.getStyle()) { |
72 return false; | 77 return false; |
73 } | 78 } |
74 | 79 |
75 // currently don't support perspective or scaling more than 3x | 80 // currently don't support perspective |
76 const GrDrawState& drawState = target->getDrawState(); | 81 const GrDrawState& drawState = target->getDrawState(); |
77 const SkMatrix& vm = drawState.getViewMatrix(); | 82 const SkMatrix& vm = drawState.getViewMatrix(); |
78 if (vm.hasPerspective() || vm.getMaxScale() > 3.0f) { | 83 if (vm.hasPerspective()) { |
79 return false; | 84 return false; |
80 } | 85 } |
81 | 86 |
82 // only support paths smaller than 64 x 64 | 87 // only support paths smaller than 64x64, scaled to less than 256x256 |
| 88 // the goal is to accelerate rendering of lots of small paths that may be sc
aling |
| 89 SkScalar maxScale = vm.getMaxScale(); |
83 const SkRect& bounds = path.getBounds(); | 90 const SkRect& bounds = path.getBounds(); |
84 return bounds.width() < 64.f && bounds.height() < 64.f; | 91 SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height()); |
| 92 return maxDim < 64.f && maxDim*maxScale < 256.f; |
85 } | 93 } |
86 | 94 |
87 | 95 |
88 GrPathRenderer::StencilSupport GrAADistanceFieldPathRenderer::onGetStencilSuppor
t( | 96 GrPathRenderer::StencilSupport GrAADistanceFieldPathRenderer::onGetStencilSuppor
t( |
89 const SkP
ath&, | 97 const SkP
ath&, |
90 const SkS
trokeRec&, | 98 const SkS
trokeRec&, |
91 const GrD
rawTarget*) const { | 99 const GrD
rawTarget*) const { |
92 return GrPathRenderer::kNoSupport_StencilSupport; | 100 return GrPathRenderer::kNoSupport_StencilSupport; |
93 } | 101 } |
94 | 102 |
(...skipping 10 matching lines...) Expand all Loading... |
105 const SkStrokeRec& stroke, | 113 const SkStrokeRec& stroke, |
106 GrDrawTarget* target, | 114 GrDrawTarget* target, |
107 bool antiAlias) { | 115 bool antiAlias) { |
108 // we've already bailed on inverse filled paths, so this is safe | 116 // we've already bailed on inverse filled paths, so this is safe |
109 if (path.isEmpty()) { | 117 if (path.isEmpty()) { |
110 return true; | 118 return true; |
111 } | 119 } |
112 | 120 |
113 SkASSERT(fContext); | 121 SkASSERT(fContext); |
114 | 122 |
| 123 // get mip level |
| 124 const GrDrawState& drawState = target->getDrawState(); |
| 125 const SkMatrix& vm = drawState.getViewMatrix(); |
| 126 SkScalar maxScale = vm.getMaxScale(); |
| 127 const SkRect& bounds = path.getBounds(); |
| 128 SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height()); |
| 129 SkScalar size = maxScale*maxDim; |
| 130 uint32_t desiredDimension; |
| 131 if (size <= kSmallMIP) { |
| 132 desiredDimension = kSmallMIP; |
| 133 } else if (size <= kMediumMIP) { |
| 134 desiredDimension = kMediumMIP; |
| 135 } else { |
| 136 desiredDimension = kLargeMIP; |
| 137 } |
| 138 |
115 // check to see if path is cached | 139 // check to see if path is cached |
116 // TODO: handle stroked vs. filled version of same path | 140 // TODO: handle stroked vs. filled version of same path |
117 PathData* pathData = fPathCache.find(path.getGenerationID()); | 141 PathData::Key key = { path.getGenerationID(), desiredDimension }; |
| 142 PathData* pathData = fPathCache.find(key); |
118 if (NULL == pathData) { | 143 if (NULL == pathData) { |
119 pathData = this->addPathToAtlas(path, stroke, antiAlias); | 144 SkScalar scale = desiredDimension/maxDim; |
| 145 pathData = this->addPathToAtlas(path, stroke, antiAlias, desiredDimensio
n, scale); |
120 if (NULL == pathData) { | 146 if (NULL == pathData) { |
121 return false; | 147 return false; |
122 } | 148 } |
123 } | 149 } |
124 | 150 |
125 // use signed distance field to render | 151 // use signed distance field to render |
126 return this->internalDrawPath(path, pathData, target); | 152 return this->internalDrawPath(path, pathData, target); |
127 } | 153 } |
128 | 154 |
129 // factor used to scale the path prior to building distance field | |
130 const SkScalar kScaleFactor = 2.0f; | |
131 // padding around path bounds to allow for antialiased pixels | 155 // padding around path bounds to allow for antialiased pixels |
132 const SkScalar kAntiAliasPad = 1.0f; | 156 const SkScalar kAntiAliasPad = 1.0f; |
133 | 157 |
134 GrAADistanceFieldPathRenderer::PathData* GrAADistanceFieldPathRenderer::addPathT
oAtlas( | 158 GrAADistanceFieldPathRenderer::PathData* GrAADistanceFieldPathRenderer::addPathT
oAtlas( |
135 const Sk
Path& path, | 159 const Sk
Path& path, |
136 const Sk
StrokeRec& stroke, | 160 const Sk
StrokeRec& stroke, |
137 bool ant
iAlias) { | 161 bool ant
iAlias, |
| 162 uint32_t
dimension, |
| 163 SkScalar
scale) { |
138 | 164 |
139 // generate distance field and add to atlas | 165 // generate distance field and add to atlas |
140 if (NULL == fAtlas) { | 166 if (NULL == fAtlas) { |
141 SkISize textureSize = SkISize::Make(ATLAS_TEXTURE_WIDTH, ATLAS_TEXTURE_H
EIGHT); | 167 SkISize textureSize = SkISize::Make(ATLAS_TEXTURE_WIDTH, ATLAS_TEXTURE_H
EIGHT); |
142 fAtlas = SkNEW_ARGS(GrAtlas, (fContext->getGpu(), kAlpha_8_GrPixelConfig
, | 168 fAtlas = SkNEW_ARGS(GrAtlas, (fContext->getGpu(), kAlpha_8_GrPixelConfig
, |
143 kNone_GrSurfaceFlags, textureSize, | 169 kNone_GrSurfaceFlags, textureSize, |
144 NUM_PLOTS_X, NUM_PLOTS_Y, false)); | 170 NUM_PLOTS_X, NUM_PLOTS_Y, false)); |
145 if (NULL == fAtlas) { | 171 if (NULL == fAtlas) { |
146 return NULL; | 172 return NULL; |
147 } | 173 } |
148 } | 174 } |
149 | 175 |
150 const SkRect& bounds = path.getBounds(); | 176 const SkRect& bounds = path.getBounds(); |
151 | 177 |
152 // generate bounding rect for bitmap draw | 178 // generate bounding rect for bitmap draw |
153 SkRect scaledBounds = bounds; | 179 SkRect scaledBounds = bounds; |
154 // scale up to improve maxification range | 180 // scale to mip level size |
155 scaledBounds.fLeft *= kScaleFactor; | 181 scaledBounds.fLeft *= scale; |
156 scaledBounds.fTop *= kScaleFactor; | 182 scaledBounds.fTop *= scale; |
157 scaledBounds.fRight *= kScaleFactor; | 183 scaledBounds.fRight *= scale; |
158 scaledBounds.fBottom *= kScaleFactor; | 184 scaledBounds.fBottom *= scale; |
159 // move the origin to an integer boundary (gives better results) | 185 // move the origin to an integer boundary (gives better results) |
160 SkScalar dx = SkScalarFraction(scaledBounds.fLeft); | 186 SkScalar dx = SkScalarFraction(scaledBounds.fLeft); |
161 SkScalar dy = SkScalarFraction(scaledBounds.fTop); | 187 SkScalar dy = SkScalarFraction(scaledBounds.fTop); |
162 scaledBounds.offset(-dx, -dy); | 188 scaledBounds.offset(-dx, -dy); |
163 // get integer boundary | 189 // get integer boundary |
164 SkIRect devPathBounds; | 190 SkIRect devPathBounds; |
165 scaledBounds.roundOut(&devPathBounds); | 191 scaledBounds.roundOut(&devPathBounds); |
166 // pad to allow room for antialiasing | 192 // pad to allow room for antialiasing |
167 devPathBounds.outset(SkScalarCeilToInt(kAntiAliasPad), SkScalarCeilToInt(kAn
tiAliasPad)); | 193 devPathBounds.outset(SkScalarCeilToInt(kAntiAliasPad), SkScalarCeilToInt(kAn
tiAliasPad)); |
168 // move origin to upper left corner | 194 // move origin to upper left corner |
169 devPathBounds.offsetTo(0,0); | 195 devPathBounds.offsetTo(0,0); |
170 | 196 |
171 // draw path to bitmap | 197 // draw path to bitmap |
172 SkMatrix drawMatrix; | 198 SkMatrix drawMatrix; |
173 drawMatrix.setTranslate(-bounds.left(), -bounds.top()); | 199 drawMatrix.setTranslate(-bounds.left(), -bounds.top()); |
174 drawMatrix.postScale(kScaleFactor, kScaleFactor); | 200 drawMatrix.postScale(scale, scale); |
175 drawMatrix.postTranslate(kAntiAliasPad, kAntiAliasPad); | 201 drawMatrix.postTranslate(kAntiAliasPad, kAntiAliasPad); |
176 GrSWMaskHelper helper(fContext); | 202 GrSWMaskHelper helper(fContext); |
177 | 203 |
178 if (!helper.init(devPathBounds, &drawMatrix)) { | 204 if (!helper.init(devPathBounds, &drawMatrix)) { |
179 return NULL; | 205 return NULL; |
180 } | 206 } |
181 helper.draw(path, stroke, SkRegion::kReplace_Op, antiAlias, 0xFF); | 207 helper.draw(path, stroke, SkRegion::kReplace_Op, antiAlias, 0xFF); |
182 | 208 |
183 // generate signed distance field | 209 // generate signed distance field |
184 devPathBounds.outset(SK_DistanceFieldPad, SK_DistanceFieldPad); | 210 devPathBounds.outset(SK_DistanceFieldPad, SK_DistanceFieldPad); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
219 goto HAS_ATLAS; | 245 goto HAS_ATLAS; |
220 } | 246 } |
221 } | 247 } |
222 | 248 |
223 return NULL; | 249 return NULL; |
224 } | 250 } |
225 | 251 |
226 HAS_ATLAS: | 252 HAS_ATLAS: |
227 // add to cache | 253 // add to cache |
228 PathData* pathData = SkNEW(PathData); | 254 PathData* pathData = SkNEW(PathData); |
229 pathData->fGenID = path.getGenerationID(); | 255 pathData->fKey.fGenID = path.getGenerationID(); |
| 256 pathData->fKey.fDimension = dimension; |
| 257 pathData->fScale = scale; |
230 pathData->fPlot = plot; | 258 pathData->fPlot = plot; |
231 // change the scaled rect to match the size of the inset distance field | 259 // change the scaled rect to match the size of the inset distance field |
232 scaledBounds.fRight = scaledBounds.fLeft + | 260 scaledBounds.fRight = scaledBounds.fLeft + |
233 SkIntToScalar(devPathBounds.width() - 2*SK_DistanceFieldInset); | 261 SkIntToScalar(devPathBounds.width() - 2*SK_DistanceFieldInset); |
234 scaledBounds.fBottom = scaledBounds.fTop + | 262 scaledBounds.fBottom = scaledBounds.fTop + |
235 SkIntToScalar(devPathBounds.height() - 2*SK_DistanceFieldInset); | 263 SkIntToScalar(devPathBounds.height() - 2*SK_DistanceFieldInset); |
236 // shift the origin to the correct place relative to the distance field | 264 // shift the origin to the correct place relative to the distance field |
237 // need to also restore the fractional translation | 265 // need to also restore the fractional translation |
238 scaledBounds.offset(-SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPad +
dx, | 266 scaledBounds.offset(-SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPad +
dx, |
239 -SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPad +
dy); | 267 -SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPad +
dy); |
(...skipping 20 matching lines...) Expand all Loading... |
260 } | 288 } |
261 plot->resetRects(); | 289 plot->resetRects(); |
262 | 290 |
263 // remove any paths that use this plot | 291 // remove any paths that use this plot |
264 PathDataList::Iter iter; | 292 PathDataList::Iter iter; |
265 iter.init(fPathList, PathDataList::Iter::kHead_IterStart); | 293 iter.init(fPathList, PathDataList::Iter::kHead_IterStart); |
266 PathData* pathData; | 294 PathData* pathData; |
267 while ((pathData = iter.get())) { | 295 while ((pathData = iter.get())) { |
268 iter.next(); | 296 iter.next(); |
269 if (plot == pathData->fPlot) { | 297 if (plot == pathData->fPlot) { |
270 fPathCache.remove(pathData->fGenID); | 298 fPathCache.remove(pathData->fKey); |
271 fPathList.remove(pathData); | 299 fPathList.remove(pathData); |
272 SkDELETE(pathData); | 300 SkDELETE(pathData); |
273 #ifdef DF_PATH_TRACKING | 301 #ifdef DF_PATH_TRACKING |
274 ++g_NumFreedPaths; | 302 ++g_NumFreedPaths; |
275 #endif | 303 #endif |
276 } | 304 } |
277 } | 305 } |
278 | 306 |
279 // tell the atlas to free the plot | 307 // tell the atlas to free the plot |
280 GrAtlas::RemovePlot(&fPlotUsage, plot); | 308 GrAtlas::RemovePlot(&fPlotUsage, plot); |
(...skipping 17 matching lines...) Expand all Loading... |
298 kSDFPathVASize); | 326 kSDFPathVASize); |
299 void* vertices = NULL; | 327 void* vertices = NULL; |
300 bool success = target->reserveVertexAndIndexSpace(4, 0, &vertices, NULL); | 328 bool success = target->reserveVertexAndIndexSpace(4, 0, &vertices, NULL); |
301 GrAlwaysAssert(success); | 329 GrAlwaysAssert(success); |
302 | 330 |
303 SkScalar dx = pathData->fBounds.fLeft; | 331 SkScalar dx = pathData->fBounds.fLeft; |
304 SkScalar dy = pathData->fBounds.fTop; | 332 SkScalar dy = pathData->fBounds.fTop; |
305 SkScalar width = pathData->fBounds.width(); | 333 SkScalar width = pathData->fBounds.width(); |
306 SkScalar height = pathData->fBounds.height(); | 334 SkScalar height = pathData->fBounds.height(); |
307 | 335 |
308 SkScalar invScale = 1.0f/kScaleFactor; | 336 SkScalar invScale = 1.0f/pathData->fScale; |
309 dx *= invScale; | 337 dx *= invScale; |
310 dy *= invScale; | 338 dy *= invScale; |
311 width *= invScale; | 339 width *= invScale; |
312 height *= invScale; | 340 height *= invScale; |
313 | 341 |
314 SkFixed tx = SkIntToFixed(pathData->fAtlasLocation.fX); | 342 SkFixed tx = SkIntToFixed(pathData->fAtlasLocation.fX); |
315 SkFixed ty = SkIntToFixed(pathData->fAtlasLocation.fY); | 343 SkFixed ty = SkIntToFixed(pathData->fAtlasLocation.fY); |
316 SkFixed tw = SkScalarToFixed(pathData->fBounds.width()); | 344 SkFixed tw = SkScalarToFixed(pathData->fBounds.width()); |
317 SkFixed th = SkScalarToFixed(pathData->fBounds.height()); | 345 SkFixed th = SkScalarToFixed(pathData->fBounds.height()); |
318 | 346 |
(...skipping 27 matching lines...) Expand all Loading... |
346 drawState->setGeometryProcessor(fCachedGeometryProcessor.get()); | 374 drawState->setGeometryProcessor(fCachedGeometryProcessor.get()); |
347 | 375 |
348 vm.mapRect(&r); | 376 vm.mapRect(&r); |
349 target->setIndexSourceToBuffer(fContext->getQuadIndexBuffer()); | 377 target->setIndexSourceToBuffer(fContext->getQuadIndexBuffer()); |
350 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6, &r); | 378 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6, &r); |
351 target->resetVertexSource(); | 379 target->resetVertexSource(); |
352 | 380 |
353 return true; | 381 return true; |
354 } | 382 } |
355 | 383 |
OLD | NEW |