Chromium Code Reviews| 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 |
|
robertphillips
2014/10/29 19:55:02
Double plot height too ?
jvanverth1
2014/10/30 12:48:28
No, they can stay 256x256. I'm just trying to doub
| |
| 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 |
|
robertphillips
2014/10/29 19:55:02
// The goal is to accelerate rendering of lots of
jvanverth1
2014/10/30 12:48:28
Done.
| |
| 88 SkScalar maxScale = vm.getMaxScale(); | |
| 83 const SkRect& bounds = path.getBounds(); | 89 const SkRect& bounds = path.getBounds(); |
| 84 return bounds.width() < 64.f && bounds.height() < 64.f; | 90 SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height()); |
| 91 return maxDim < 64.f && maxDim*maxScale < 256.f; | |
| 85 } | 92 } |
| 86 | 93 |
| 87 | 94 |
| 88 GrPathRenderer::StencilSupport GrAADistanceFieldPathRenderer::onGetStencilSuppor t( | 95 GrPathRenderer::StencilSupport GrAADistanceFieldPathRenderer::onGetStencilSuppor t( |
| 89 const SkP ath&, | 96 const SkP ath&, |
| 90 const SkS trokeRec&, | 97 const SkS trokeRec&, |
| 91 const GrD rawTarget*) const { | 98 const GrD rawTarget*) const { |
| 92 return GrPathRenderer::kNoSupport_StencilSupport; | 99 return GrPathRenderer::kNoSupport_StencilSupport; |
| 93 } | 100 } |
| 94 | 101 |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 105 const SkStrokeRec& stroke, | 112 const SkStrokeRec& stroke, |
| 106 GrDrawTarget* target, | 113 GrDrawTarget* target, |
| 107 bool antiAlias) { | 114 bool antiAlias) { |
| 108 // we've already bailed on inverse filled paths, so this is safe | 115 // we've already bailed on inverse filled paths, so this is safe |
| 109 if (path.isEmpty()) { | 116 if (path.isEmpty()) { |
| 110 return true; | 117 return true; |
| 111 } | 118 } |
| 112 | 119 |
| 113 SkASSERT(fContext); | 120 SkASSERT(fContext); |
| 114 | 121 |
| 122 // get mip level | |
| 123 const GrDrawState& drawState = target->getDrawState(); | |
| 124 const SkMatrix& vm = drawState.getViewMatrix(); | |
| 125 SkScalar maxScale = vm.getMaxScale(); | |
| 126 const SkRect& bounds = path.getBounds(); | |
| 127 SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height()); | |
| 128 SkScalar size = maxScale*maxDim; | |
| 129 uint32_t mipLevel; | |
| 130 if (size <= kSmallMIP) { | |
| 131 mipLevel = kSmallMIP; | |
| 132 } else if (size <= kMediumMIP) { | |
| 133 mipLevel = kMediumMIP; | |
| 134 } else { | |
| 135 mipLevel = kLargeMIP; | |
| 136 } | |
| 137 | |
| 115 // check to see if path is cached | 138 // check to see if path is cached |
| 116 // TODO: handle stroked vs. filled version of same path | 139 // TODO: handle stroked vs. filled version of same path |
| 117 PathData* pathData = fPathCache.find(path.getGenerationID()); | 140 PathData::Key key = { path.getGenerationID(), mipLevel }; |
| 141 PathData* pathData = fPathCache.find(key); | |
| 118 if (NULL == pathData) { | 142 if (NULL == pathData) { |
| 119 pathData = this->addPathToAtlas(path, stroke, antiAlias); | 143 SkScalar scale = mipLevel/maxDim; |
| 144 pathData = this->addPathToAtlas(path, stroke, antiAlias, mipLevel, scale ); | |
| 120 if (NULL == pathData) { | 145 if (NULL == pathData) { |
| 121 return false; | 146 return false; |
| 122 } | 147 } |
| 123 } | 148 } |
| 124 | 149 |
| 125 // use signed distance field to render | 150 // use signed distance field to render |
| 126 return this->internalDrawPath(path, pathData, target); | 151 return this->internalDrawPath(path, pathData, target); |
| 127 } | 152 } |
| 128 | 153 |
| 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 | 154 // padding around path bounds to allow for antialiased pixels |
| 132 const SkScalar kAntiAliasPad = 1.0f; | 155 const SkScalar kAntiAliasPad = 1.0f; |
| 133 | 156 |
| 134 GrAADistanceFieldPathRenderer::PathData* GrAADistanceFieldPathRenderer::addPathT oAtlas( | 157 GrAADistanceFieldPathRenderer::PathData* GrAADistanceFieldPathRenderer::addPathT oAtlas( |
| 135 const Sk Path& path, | 158 const Sk Path& path, |
| 136 const Sk StrokeRec& stroke, | 159 const Sk StrokeRec& stroke, |
| 137 bool ant iAlias) { | 160 bool ant iAlias, |
| 161 uint32_t mipLevel, | |
| 162 SkScalar scale) { | |
| 138 | 163 |
| 139 // generate distance field and add to atlas | 164 // generate distance field and add to atlas |
| 140 if (NULL == fAtlas) { | 165 if (NULL == fAtlas) { |
| 141 SkISize textureSize = SkISize::Make(ATLAS_TEXTURE_WIDTH, ATLAS_TEXTURE_H EIGHT); | 166 SkISize textureSize = SkISize::Make(ATLAS_TEXTURE_WIDTH, ATLAS_TEXTURE_H EIGHT); |
| 142 fAtlas = SkNEW_ARGS(GrAtlas, (fContext->getGpu(), kAlpha_8_GrPixelConfig , | 167 fAtlas = SkNEW_ARGS(GrAtlas, (fContext->getGpu(), kAlpha_8_GrPixelConfig , |
| 143 kNone_GrSurfaceFlags, textureSize, | 168 kNone_GrSurfaceFlags, textureSize, |
| 144 NUM_PLOTS_X, NUM_PLOTS_Y, false)); | 169 NUM_PLOTS_X, NUM_PLOTS_Y, false)); |
| 145 if (NULL == fAtlas) { | 170 if (NULL == fAtlas) { |
| 146 return NULL; | 171 return NULL; |
| 147 } | 172 } |
| 148 } | 173 } |
| 149 | 174 |
| 150 const SkRect& bounds = path.getBounds(); | 175 const SkRect& bounds = path.getBounds(); |
| 151 | 176 |
| 152 // generate bounding rect for bitmap draw | 177 // generate bounding rect for bitmap draw |
| 153 SkRect scaledBounds = bounds; | 178 SkRect scaledBounds = bounds; |
| 154 // scale up to improve maxification range | 179 // scale to mip level size |
| 155 scaledBounds.fLeft *= kScaleFactor; | 180 scaledBounds.fLeft *= scale; |
| 156 scaledBounds.fTop *= kScaleFactor; | 181 scaledBounds.fTop *= scale; |
| 157 scaledBounds.fRight *= kScaleFactor; | 182 scaledBounds.fRight *= scale; |
| 158 scaledBounds.fBottom *= kScaleFactor; | 183 scaledBounds.fBottom *= scale; |
| 159 // move the origin to an integer boundary (gives better results) | 184 // move the origin to an integer boundary (gives better results) |
| 160 SkScalar dx = SkScalarFraction(scaledBounds.fLeft); | 185 SkScalar dx = SkScalarFraction(scaledBounds.fLeft); |
| 161 SkScalar dy = SkScalarFraction(scaledBounds.fTop); | 186 SkScalar dy = SkScalarFraction(scaledBounds.fTop); |
| 162 scaledBounds.offset(-dx, -dy); | 187 scaledBounds.offset(-dx, -dy); |
| 163 // get integer boundary | 188 // get integer boundary |
| 164 SkIRect devPathBounds; | 189 SkIRect devPathBounds; |
| 165 scaledBounds.roundOut(&devPathBounds); | 190 scaledBounds.roundOut(&devPathBounds); |
| 166 // pad to allow room for antialiasing | 191 // pad to allow room for antialiasing |
| 167 devPathBounds.outset(SkScalarCeilToInt(kAntiAliasPad), SkScalarCeilToInt(kAn tiAliasPad)); | 192 devPathBounds.outset(SkScalarCeilToInt(kAntiAliasPad), SkScalarCeilToInt(kAn tiAliasPad)); |
| 168 // move origin to upper left corner | 193 // move origin to upper left corner |
| 169 devPathBounds.offsetTo(0,0); | 194 devPathBounds.offsetTo(0,0); |
| 170 | 195 |
| 171 // draw path to bitmap | 196 // draw path to bitmap |
| 172 SkMatrix drawMatrix; | 197 SkMatrix drawMatrix; |
| 173 drawMatrix.setTranslate(-bounds.left(), -bounds.top()); | 198 drawMatrix.setTranslate(-bounds.left(), -bounds.top()); |
| 174 drawMatrix.postScale(kScaleFactor, kScaleFactor); | 199 drawMatrix.postScale(scale, scale); |
| 175 drawMatrix.postTranslate(kAntiAliasPad, kAntiAliasPad); | 200 drawMatrix.postTranslate(kAntiAliasPad, kAntiAliasPad); |
| 176 GrSWMaskHelper helper(fContext); | 201 GrSWMaskHelper helper(fContext); |
| 177 | 202 |
| 178 if (!helper.init(devPathBounds, &drawMatrix)) { | 203 if (!helper.init(devPathBounds, &drawMatrix)) { |
| 179 return NULL; | 204 return NULL; |
| 180 } | 205 } |
| 181 helper.draw(path, stroke, SkRegion::kReplace_Op, antiAlias, 0xFF); | 206 helper.draw(path, stroke, SkRegion::kReplace_Op, antiAlias, 0xFF); |
| 182 | 207 |
| 183 // generate signed distance field | 208 // generate signed distance field |
| 184 devPathBounds.outset(SK_DistanceFieldPad, SK_DistanceFieldPad); | 209 devPathBounds.outset(SK_DistanceFieldPad, SK_DistanceFieldPad); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 219 goto HAS_ATLAS; | 244 goto HAS_ATLAS; |
| 220 } | 245 } |
| 221 } | 246 } |
| 222 | 247 |
| 223 return NULL; | 248 return NULL; |
| 224 } | 249 } |
| 225 | 250 |
| 226 HAS_ATLAS: | 251 HAS_ATLAS: |
| 227 // add to cache | 252 // add to cache |
| 228 PathData* pathData = SkNEW(PathData); | 253 PathData* pathData = SkNEW(PathData); |
| 229 pathData->fGenID = path.getGenerationID(); | 254 pathData->fKey.fGenID = path.getGenerationID(); |
| 255 pathData->fKey.fMipLevel = mipLevel; | |
| 256 pathData->fScale = scale; | |
| 230 pathData->fPlot = plot; | 257 pathData->fPlot = plot; |
| 231 // change the scaled rect to match the size of the inset distance field | 258 // change the scaled rect to match the size of the inset distance field |
| 232 scaledBounds.fRight = scaledBounds.fLeft + | 259 scaledBounds.fRight = scaledBounds.fLeft + |
| 233 SkIntToScalar(devPathBounds.width() - 2*SK_DistanceFieldInset); | 260 SkIntToScalar(devPathBounds.width() - 2*SK_DistanceFieldInset); |
| 234 scaledBounds.fBottom = scaledBounds.fTop + | 261 scaledBounds.fBottom = scaledBounds.fTop + |
| 235 SkIntToScalar(devPathBounds.height() - 2*SK_DistanceFieldInset); | 262 SkIntToScalar(devPathBounds.height() - 2*SK_DistanceFieldInset); |
| 236 // shift the origin to the correct place relative to the distance field | 263 // shift the origin to the correct place relative to the distance field |
| 237 // need to also restore the fractional translation | 264 // need to also restore the fractional translation |
| 238 scaledBounds.offset(-SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPad + dx, | 265 scaledBounds.offset(-SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPad + dx, |
| 239 -SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPad + dy); | 266 -SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPad + dy); |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 260 } | 287 } |
| 261 plot->resetRects(); | 288 plot->resetRects(); |
| 262 | 289 |
| 263 // remove any paths that use this plot | 290 // remove any paths that use this plot |
| 264 PathDataList::Iter iter; | 291 PathDataList::Iter iter; |
| 265 iter.init(fPathList, PathDataList::Iter::kHead_IterStart); | 292 iter.init(fPathList, PathDataList::Iter::kHead_IterStart); |
| 266 PathData* pathData; | 293 PathData* pathData; |
| 267 while ((pathData = iter.get())) { | 294 while ((pathData = iter.get())) { |
| 268 iter.next(); | 295 iter.next(); |
| 269 if (plot == pathData->fPlot) { | 296 if (plot == pathData->fPlot) { |
| 270 fPathCache.remove(pathData->fGenID); | 297 fPathCache.remove(pathData->fKey); |
| 271 fPathList.remove(pathData); | 298 fPathList.remove(pathData); |
| 272 SkDELETE(pathData); | 299 SkDELETE(pathData); |
| 273 #ifdef DF_PATH_TRACKING | 300 #ifdef DF_PATH_TRACKING |
| 274 ++g_NumFreedPaths; | 301 ++g_NumFreedPaths; |
| 275 #endif | 302 #endif |
| 276 } | 303 } |
| 277 } | 304 } |
| 278 | 305 |
| 279 // tell the atlas to free the plot | 306 // tell the atlas to free the plot |
| 280 GrAtlas::RemovePlot(&fPlotUsage, plot); | 307 GrAtlas::RemovePlot(&fPlotUsage, plot); |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 298 kSDFPathVASize); | 325 kSDFPathVASize); |
| 299 void* vertices = NULL; | 326 void* vertices = NULL; |
| 300 bool success = target->reserveVertexAndIndexSpace(4, 0, &vertices, NULL); | 327 bool success = target->reserveVertexAndIndexSpace(4, 0, &vertices, NULL); |
| 301 GrAlwaysAssert(success); | 328 GrAlwaysAssert(success); |
| 302 | 329 |
| 303 SkScalar dx = pathData->fBounds.fLeft; | 330 SkScalar dx = pathData->fBounds.fLeft; |
| 304 SkScalar dy = pathData->fBounds.fTop; | 331 SkScalar dy = pathData->fBounds.fTop; |
| 305 SkScalar width = pathData->fBounds.width(); | 332 SkScalar width = pathData->fBounds.width(); |
| 306 SkScalar height = pathData->fBounds.height(); | 333 SkScalar height = pathData->fBounds.height(); |
| 307 | 334 |
| 308 SkScalar invScale = 1.0f/kScaleFactor; | 335 SkScalar invScale = 1.0f/pathData->fScale; |
| 309 dx *= invScale; | 336 dx *= invScale; |
| 310 dy *= invScale; | 337 dy *= invScale; |
| 311 width *= invScale; | 338 width *= invScale; |
| 312 height *= invScale; | 339 height *= invScale; |
| 313 | 340 |
| 314 SkFixed tx = SkIntToFixed(pathData->fAtlasLocation.fX); | 341 SkFixed tx = SkIntToFixed(pathData->fAtlasLocation.fX); |
| 315 SkFixed ty = SkIntToFixed(pathData->fAtlasLocation.fY); | 342 SkFixed ty = SkIntToFixed(pathData->fAtlasLocation.fY); |
| 316 SkFixed tw = SkScalarToFixed(pathData->fBounds.width()); | 343 SkFixed tw = SkScalarToFixed(pathData->fBounds.width()); |
| 317 SkFixed th = SkScalarToFixed(pathData->fBounds.height()); | 344 SkFixed th = SkScalarToFixed(pathData->fBounds.height()); |
| 318 | 345 |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 346 drawState->setGeometryProcessor(fCachedGeometryProcessor.get()); | 373 drawState->setGeometryProcessor(fCachedGeometryProcessor.get()); |
| 347 | 374 |
| 348 vm.mapRect(&r); | 375 vm.mapRect(&r); |
| 349 target->setIndexSourceToBuffer(fContext->getQuadIndexBuffer()); | 376 target->setIndexSourceToBuffer(fContext->getQuadIndexBuffer()); |
| 350 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6, &r); | 377 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6, &r); |
| 351 target->resetVertexSource(); | 378 target->resetVertexSource(); |
| 352 | 379 |
| 353 return true; | 380 return true; |
| 354 } | 381 } |
| 355 | 382 |
| OLD | NEW |