jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 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" |
egdaniel | 8dd688b | 2015-01-22 10:16:09 -0800 | [diff] [blame] | 13 | #include "GrPipelineBuilder.h" |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 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 | |
reed | e4ef1ca | 2015-02-17 18:38:38 -0800 | [diff] [blame] | 22 | #define ATLAS_TEXTURE_WIDTH 1024 |
jvanverth | b61283f | 2014-10-30 05:57:21 -0700 | [diff] [blame] | 23 | #define ATLAS_TEXTURE_HEIGHT 2048 |
reed | e4ef1ca | 2015-02-17 18:38:38 -0800 | [diff] [blame] | 24 | #define PLOT_WIDTH 256 |
| 25 | #define PLOT_HEIGHT 256 |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 26 | |
| 27 | #define NUM_PLOTS_X (ATLAS_TEXTURE_WIDTH / PLOT_WIDTH) |
| 28 | #define NUM_PLOTS_Y (ATLAS_TEXTURE_HEIGHT / PLOT_HEIGHT) |
| 29 | |
| 30 | SK_CONF_DECLARE(bool, c_DumpPathCache, "gpu.dumpPathCache", false, |
| 31 | "Dump the contents of the path cache before every purge."); |
| 32 | |
jvanverth | b3eb687 | 2014-10-24 07:12:51 -0700 | [diff] [blame] | 33 | #ifdef DF_PATH_TRACKING |
| 34 | static int g_NumCachedPaths = 0; |
| 35 | static int g_NumFreedPaths = 0; |
| 36 | #endif |
| 37 | |
jvanverth | b61283f | 2014-10-30 05:57:21 -0700 | [diff] [blame] | 38 | // mip levels |
| 39 | static const int kSmallMIP = 32; |
jvanverth | ada68ef | 2014-11-03 14:00:24 -0800 | [diff] [blame] | 40 | static const int kMediumMIP = 78; |
| 41 | static const int kLargeMIP = 192; |
jvanverth | b61283f | 2014-10-30 05:57:21 -0700 | [diff] [blame] | 42 | |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 43 | //////////////////////////////////////////////////////////////////////////////// |
jvanverth | 6d22eca | 2014-10-28 11:10:48 -0700 | [diff] [blame] | 44 | GrAADistanceFieldPathRenderer::GrAADistanceFieldPathRenderer(GrContext* context) |
| 45 | : fContext(context) |
| 46 | , fAtlas(NULL) |
| 47 | , fEffectFlags(kInvalid_DistanceFieldEffectFlag) { |
| 48 | } |
| 49 | |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 50 | GrAADistanceFieldPathRenderer::~GrAADistanceFieldPathRenderer() { |
| 51 | PathDataList::Iter iter; |
| 52 | iter.init(fPathList, PathDataList::Iter::kHead_IterStart); |
| 53 | PathData* pathData; |
| 54 | while ((pathData = iter.get())) { |
| 55 | iter.next(); |
| 56 | fPathList.remove(pathData); |
| 57 | SkDELETE(pathData); |
| 58 | } |
| 59 | |
| 60 | SkDELETE(fAtlas); |
jvanverth | b3eb687 | 2014-10-24 07:12:51 -0700 | [diff] [blame] | 61 | |
| 62 | #ifdef DF_PATH_TRACKING |
| 63 | SkDebugf("Cached paths: %d, freed paths: %d\n", g_NumCachedPaths, g_NumFreedPaths); |
| 64 | #endif |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 65 | } |
| 66 | |
| 67 | //////////////////////////////////////////////////////////////////////////////// |
joshualitt | 9853cce | 2014-11-17 14:22:48 -0800 | [diff] [blame] | 68 | bool GrAADistanceFieldPathRenderer::canDrawPath(const GrDrawTarget* target, |
egdaniel | 8dd688b | 2015-01-22 10:16:09 -0800 | [diff] [blame] | 69 | const GrPipelineBuilder* pipelineBuilder, |
joshualitt | 8059eb9 | 2014-12-29 15:10:07 -0800 | [diff] [blame] | 70 | const SkMatrix& viewMatrix, |
joshualitt | 9853cce | 2014-11-17 14:22:48 -0800 | [diff] [blame] | 71 | const SkPath& path, |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 72 | const SkStrokeRec& stroke, |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 73 | bool antiAlias) const { |
jvanverth | b3eb687 | 2014-10-24 07:12:51 -0700 | [diff] [blame] | 74 | |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 75 | // TODO: Support inverse fill |
| 76 | // TODO: Support strokes |
| 77 | if (!target->caps()->shaderDerivativeSupport() || !antiAlias || path.isInverseFillType() |
jvanverth | b3eb687 | 2014-10-24 07:12:51 -0700 | [diff] [blame] | 78 | || path.isVolatile() || SkStrokeRec::kFill_Style != stroke.getStyle()) { |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 79 | return false; |
| 80 | } |
| 81 | |
jvanverth | b61283f | 2014-10-30 05:57:21 -0700 | [diff] [blame] | 82 | // currently don't support perspective |
joshualitt | 8059eb9 | 2014-12-29 15:10:07 -0800 | [diff] [blame] | 83 | if (viewMatrix.hasPerspective()) { |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 84 | return false; |
| 85 | } |
| 86 | |
jvanverth | b61283f | 2014-10-30 05:57:21 -0700 | [diff] [blame] | 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 scaling |
joshualitt | 8059eb9 | 2014-12-29 15:10:07 -0800 | [diff] [blame] | 89 | SkScalar maxScale = viewMatrix.getMaxScale(); |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 90 | const SkRect& bounds = path.getBounds(); |
jvanverth | b61283f | 2014-10-30 05:57:21 -0700 | [diff] [blame] | 91 | SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height()); |
| 92 | return maxDim < 64.f && maxDim*maxScale < 256.f; |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 93 | } |
| 94 | |
| 95 | |
joshualitt | 9853cce | 2014-11-17 14:22:48 -0800 | [diff] [blame] | 96 | GrPathRenderer::StencilSupport |
| 97 | GrAADistanceFieldPathRenderer::onGetStencilSupport(const GrDrawTarget*, |
egdaniel | 8dd688b | 2015-01-22 10:16:09 -0800 | [diff] [blame] | 98 | const GrPipelineBuilder*, |
joshualitt | 9853cce | 2014-11-17 14:22:48 -0800 | [diff] [blame] | 99 | const SkPath&, |
| 100 | const SkStrokeRec&) const { |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 101 | return GrPathRenderer::kNoSupport_StencilSupport; |
| 102 | } |
| 103 | |
| 104 | //////////////////////////////////////////////////////////////////////////////// |
| 105 | |
joshualitt | 9853cce | 2014-11-17 14:22:48 -0800 | [diff] [blame] | 106 | bool GrAADistanceFieldPathRenderer::onDrawPath(GrDrawTarget* target, |
egdaniel | 8dd688b | 2015-01-22 10:16:09 -0800 | [diff] [blame] | 107 | GrPipelineBuilder* pipelineBuilder, |
joshualitt | 2e3b3e3 | 2014-12-09 13:31:14 -0800 | [diff] [blame] | 108 | GrColor color, |
joshualitt | 8059eb9 | 2014-12-29 15:10:07 -0800 | [diff] [blame] | 109 | const SkMatrix& viewMatrix, |
joshualitt | 9853cce | 2014-11-17 14:22:48 -0800 | [diff] [blame] | 110 | const SkPath& path, |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 111 | const SkStrokeRec& stroke, |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 112 | bool antiAlias) { |
| 113 | // we've already bailed on inverse filled paths, so this is safe |
| 114 | if (path.isEmpty()) { |
| 115 | return true; |
| 116 | } |
| 117 | |
| 118 | SkASSERT(fContext); |
| 119 | |
jvanverth | b61283f | 2014-10-30 05:57:21 -0700 | [diff] [blame] | 120 | // get mip level |
joshualitt | 8059eb9 | 2014-12-29 15:10:07 -0800 | [diff] [blame] | 121 | SkScalar maxScale = viewMatrix.getMaxScale(); |
jvanverth | b61283f | 2014-10-30 05:57:21 -0700 | [diff] [blame] | 122 | const SkRect& bounds = path.getBounds(); |
| 123 | SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height()); |
| 124 | SkScalar size = maxScale*maxDim; |
| 125 | uint32_t desiredDimension; |
| 126 | if (size <= kSmallMIP) { |
| 127 | desiredDimension = kSmallMIP; |
| 128 | } else if (size <= kMediumMIP) { |
| 129 | desiredDimension = kMediumMIP; |
| 130 | } else { |
| 131 | desiredDimension = kLargeMIP; |
| 132 | } |
| 133 | |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 134 | // check to see if path is cached |
| 135 | // TODO: handle stroked vs. filled version of same path |
jvanverth | b61283f | 2014-10-30 05:57:21 -0700 | [diff] [blame] | 136 | PathData::Key key = { path.getGenerationID(), desiredDimension }; |
| 137 | PathData* pathData = fPathCache.find(key); |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 138 | if (NULL == pathData) { |
jvanverth | b61283f | 2014-10-30 05:57:21 -0700 | [diff] [blame] | 139 | SkScalar scale = desiredDimension/maxDim; |
| 140 | pathData = this->addPathToAtlas(path, stroke, antiAlias, desiredDimension, scale); |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 141 | if (NULL == pathData) { |
| 142 | return false; |
| 143 | } |
| 144 | } |
| 145 | |
| 146 | // use signed distance field to render |
egdaniel | 8dd688b | 2015-01-22 10:16:09 -0800 | [diff] [blame] | 147 | return this->internalDrawPath(target, pipelineBuilder, color, viewMatrix, path, pathData); |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 148 | } |
| 149 | |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 150 | // padding around path bounds to allow for antialiased pixels |
| 151 | const SkScalar kAntiAliasPad = 1.0f; |
| 152 | |
joshualitt | 9491f7f | 2015-02-11 11:33:38 -0800 | [diff] [blame] | 153 | inline bool GrAADistanceFieldPathRenderer::uploadPath(GrPlot** plot, SkIPoint16* atlasLocation, |
| 154 | int width, int height, void* dfStorage) { |
| 155 | *plot = fAtlas->addToAtlas(&fPlotUsage, width, height, dfStorage, atlasLocation); |
| 156 | |
| 157 | // if atlas full |
| 158 | if (NULL == *plot) { |
| 159 | if (this->freeUnusedPlot()) { |
| 160 | *plot = fAtlas->addToAtlas(&fPlotUsage, width, height, dfStorage, atlasLocation); |
| 161 | if (*plot) { |
| 162 | return true; |
| 163 | } |
| 164 | } |
| 165 | |
| 166 | if (c_DumpPathCache) { |
| 167 | #ifdef SK_DEVELOPER |
| 168 | GrTexture* texture = fAtlas->getTexture(); |
| 169 | texture->surfacePriv().savePixels("pathcache.png"); |
| 170 | #endif |
| 171 | } |
| 172 | |
| 173 | // before we purge the cache, we must flush any accumulated draws |
| 174 | fContext->flush(); |
| 175 | |
| 176 | if (this->freeUnusedPlot()) { |
| 177 | *plot = fAtlas->addToAtlas(&fPlotUsage, width, height, dfStorage, atlasLocation); |
| 178 | if (*plot) { |
| 179 | return true; |
| 180 | } |
| 181 | } |
| 182 | return false; |
| 183 | } |
| 184 | return true; |
| 185 | } |
| 186 | |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 187 | GrAADistanceFieldPathRenderer::PathData* GrAADistanceFieldPathRenderer::addPathToAtlas( |
| 188 | const SkPath& path, |
| 189 | const SkStrokeRec& stroke, |
jvanverth | b61283f | 2014-10-30 05:57:21 -0700 | [diff] [blame] | 190 | bool antiAlias, |
| 191 | uint32_t dimension, |
| 192 | SkScalar scale) { |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 193 | |
| 194 | // generate distance field and add to atlas |
| 195 | if (NULL == fAtlas) { |
| 196 | SkISize textureSize = SkISize::Make(ATLAS_TEXTURE_WIDTH, ATLAS_TEXTURE_HEIGHT); |
| 197 | fAtlas = SkNEW_ARGS(GrAtlas, (fContext->getGpu(), kAlpha_8_GrPixelConfig, |
bsalomon | f2703d8 | 2014-10-28 14:33:06 -0700 | [diff] [blame] | 198 | kNone_GrSurfaceFlags, textureSize, |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 199 | NUM_PLOTS_X, NUM_PLOTS_Y, false)); |
| 200 | if (NULL == fAtlas) { |
| 201 | return NULL; |
| 202 | } |
| 203 | } |
| 204 | |
| 205 | const SkRect& bounds = path.getBounds(); |
| 206 | |
| 207 | // generate bounding rect for bitmap draw |
| 208 | SkRect scaledBounds = bounds; |
jvanverth | b61283f | 2014-10-30 05:57:21 -0700 | [diff] [blame] | 209 | // scale to mip level size |
| 210 | scaledBounds.fLeft *= scale; |
| 211 | scaledBounds.fTop *= scale; |
| 212 | scaledBounds.fRight *= scale; |
| 213 | scaledBounds.fBottom *= scale; |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 214 | // move the origin to an integer boundary (gives better results) |
| 215 | SkScalar dx = SkScalarFraction(scaledBounds.fLeft); |
| 216 | SkScalar dy = SkScalarFraction(scaledBounds.fTop); |
| 217 | scaledBounds.offset(-dx, -dy); |
| 218 | // get integer boundary |
| 219 | SkIRect devPathBounds; |
| 220 | scaledBounds.roundOut(&devPathBounds); |
| 221 | // pad to allow room for antialiasing |
| 222 | devPathBounds.outset(SkScalarCeilToInt(kAntiAliasPad), SkScalarCeilToInt(kAntiAliasPad)); |
| 223 | // move origin to upper left corner |
| 224 | devPathBounds.offsetTo(0,0); |
| 225 | |
| 226 | // draw path to bitmap |
| 227 | SkMatrix drawMatrix; |
| 228 | drawMatrix.setTranslate(-bounds.left(), -bounds.top()); |
jvanverth | b61283f | 2014-10-30 05:57:21 -0700 | [diff] [blame] | 229 | drawMatrix.postScale(scale, scale); |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 230 | drawMatrix.postTranslate(kAntiAliasPad, kAntiAliasPad); |
| 231 | GrSWMaskHelper helper(fContext); |
| 232 | |
| 233 | if (!helper.init(devPathBounds, &drawMatrix)) { |
| 234 | return NULL; |
| 235 | } |
| 236 | helper.draw(path, stroke, SkRegion::kReplace_Op, antiAlias, 0xFF); |
| 237 | |
| 238 | // generate signed distance field |
| 239 | devPathBounds.outset(SK_DistanceFieldPad, SK_DistanceFieldPad); |
| 240 | int width = devPathBounds.width(); |
| 241 | int height = devPathBounds.height(); |
| 242 | SkAutoSMalloc<1024> dfStorage(width*height*sizeof(unsigned char)); |
| 243 | helper.toSDF((unsigned char*) dfStorage.get()); |
| 244 | |
| 245 | // add to atlas |
joshualitt | 9491f7f | 2015-02-11 11:33:38 -0800 | [diff] [blame] | 246 | GrPlot* plot; |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 247 | SkIPoint16 atlasLocation; |
joshualitt | 9491f7f | 2015-02-11 11:33:38 -0800 | [diff] [blame] | 248 | if (!this->uploadPath(&plot, &atlasLocation, width, height, dfStorage.get())) { |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 249 | return NULL; |
| 250 | } |
joshualitt | 9491f7f | 2015-02-11 11:33:38 -0800 | [diff] [blame] | 251 | |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 252 | // add to cache |
| 253 | PathData* pathData = SkNEW(PathData); |
jvanverth | b61283f | 2014-10-30 05:57:21 -0700 | [diff] [blame] | 254 | pathData->fKey.fGenID = path.getGenerationID(); |
| 255 | pathData->fKey.fDimension = dimension; |
| 256 | pathData->fScale = scale; |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 257 | pathData->fPlot = plot; |
| 258 | // change the scaled rect to match the size of the inset distance field |
| 259 | scaledBounds.fRight = scaledBounds.fLeft + |
| 260 | SkIntToScalar(devPathBounds.width() - 2*SK_DistanceFieldInset); |
| 261 | scaledBounds.fBottom = scaledBounds.fTop + |
| 262 | SkIntToScalar(devPathBounds.height() - 2*SK_DistanceFieldInset); |
| 263 | // shift the origin to the correct place relative to the distance field |
| 264 | // need to also restore the fractional translation |
| 265 | scaledBounds.offset(-SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPad + dx, |
| 266 | -SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPad + dy); |
| 267 | pathData->fBounds = scaledBounds; |
| 268 | // origin we render from is inset from distance field edge |
| 269 | atlasLocation.fX += SK_DistanceFieldInset; |
| 270 | atlasLocation.fY += SK_DistanceFieldInset; |
| 271 | pathData->fAtlasLocation = atlasLocation; |
| 272 | |
| 273 | fPathCache.add(pathData); |
| 274 | fPathList.addToTail(pathData); |
jvanverth | b3eb687 | 2014-10-24 07:12:51 -0700 | [diff] [blame] | 275 | #ifdef DF_PATH_TRACKING |
| 276 | ++g_NumCachedPaths; |
| 277 | #endif |
| 278 | |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 279 | return pathData; |
| 280 | } |
| 281 | |
| 282 | bool GrAADistanceFieldPathRenderer::freeUnusedPlot() { |
| 283 | // find an unused plot |
| 284 | GrPlot* plot = fAtlas->getUnusedPlot(); |
| 285 | if (NULL == plot) { |
| 286 | return false; |
| 287 | } |
| 288 | plot->resetRects(); |
| 289 | |
| 290 | // remove any paths that use this plot |
| 291 | PathDataList::Iter iter; |
| 292 | iter.init(fPathList, PathDataList::Iter::kHead_IterStart); |
| 293 | PathData* pathData; |
| 294 | while ((pathData = iter.get())) { |
| 295 | iter.next(); |
| 296 | if (plot == pathData->fPlot) { |
jvanverth | b61283f | 2014-10-30 05:57:21 -0700 | [diff] [blame] | 297 | fPathCache.remove(pathData->fKey); |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 298 | fPathList.remove(pathData); |
| 299 | SkDELETE(pathData); |
jvanverth | b3eb687 | 2014-10-24 07:12:51 -0700 | [diff] [blame] | 300 | #ifdef DF_PATH_TRACKING |
| 301 | ++g_NumFreedPaths; |
| 302 | #endif |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 303 | } |
| 304 | } |
| 305 | |
| 306 | // tell the atlas to free the plot |
| 307 | GrAtlas::RemovePlot(&fPlotUsage, plot); |
| 308 | |
| 309 | return true; |
| 310 | } |
| 311 | |
joshualitt | 9853cce | 2014-11-17 14:22:48 -0800 | [diff] [blame] | 312 | bool GrAADistanceFieldPathRenderer::internalDrawPath(GrDrawTarget* target, |
egdaniel | 8dd688b | 2015-01-22 10:16:09 -0800 | [diff] [blame] | 313 | GrPipelineBuilder* pipelineBuilder, |
joshualitt | 2e3b3e3 | 2014-12-09 13:31:14 -0800 | [diff] [blame] | 314 | GrColor color, |
joshualitt | 8059eb9 | 2014-12-29 15:10:07 -0800 | [diff] [blame] | 315 | const SkMatrix& viewMatrix, |
joshualitt | 9853cce | 2014-11-17 14:22:48 -0800 | [diff] [blame] | 316 | const SkPath& path, |
| 317 | const PathData* pathData) { |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 318 | GrTexture* texture = fAtlas->getTexture(); |
egdaniel | 8dd688b | 2015-01-22 10:16:09 -0800 | [diff] [blame] | 319 | GrPipelineBuilder::AutoRestoreEffects are(pipelineBuilder); |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 320 | |
| 321 | SkASSERT(pathData->fPlot); |
| 322 | GrDrawTarget::DrawToken drawToken = target->getCurrentDrawToken(); |
| 323 | pathData->fPlot->setDrawToken(drawToken); |
| 324 | |
joshualitt | 2dd1ae0 | 2014-12-03 06:24:10 -0800 | [diff] [blame] | 325 | // set up any flags |
| 326 | uint32_t flags = 0; |
joshualitt | 8059eb9 | 2014-12-29 15:10:07 -0800 | [diff] [blame] | 327 | flags |= viewMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0; |
joshualitt | 2dd1ae0 | 2014-12-03 06:24:10 -0800 | [diff] [blame] | 328 | |
| 329 | GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_FilterMode); |
joshualitt | 8059eb9 | 2014-12-29 15:10:07 -0800 | [diff] [blame] | 330 | if (flags != fEffectFlags || fCachedGeometryProcessor->color() != color || |
| 331 | !fCachedGeometryProcessor->viewMatrix().cheapEqualTo(viewMatrix)) { |
joshualitt | 2e3b3e3 | 2014-12-09 13:31:14 -0800 | [diff] [blame] | 332 | fCachedGeometryProcessor.reset(GrDistanceFieldNoGammaTextureEffect::Create(color, |
joshualitt | 8059eb9 | 2014-12-29 15:10:07 -0800 | [diff] [blame] | 333 | viewMatrix, |
joshualitt | 2e3b3e3 | 2014-12-09 13:31:14 -0800 | [diff] [blame] | 334 | texture, |
joshualitt | 2dd1ae0 | 2014-12-03 06:24:10 -0800 | [diff] [blame] | 335 | params, |
joshualitt | 56995b5 | 2014-12-11 15:44:02 -0800 | [diff] [blame] | 336 | flags, |
| 337 | false)); |
joshualitt | 2dd1ae0 | 2014-12-03 06:24:10 -0800 | [diff] [blame] | 338 | fEffectFlags = flags; |
| 339 | } |
joshualitt | 2dd1ae0 | 2014-12-03 06:24:10 -0800 | [diff] [blame] | 340 | |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 341 | void* vertices = NULL; |
joshualitt | 2dd1ae0 | 2014-12-03 06:24:10 -0800 | [diff] [blame] | 342 | bool success = target->reserveVertexAndIndexSpace(4, |
| 343 | fCachedGeometryProcessor->getVertexStride(), |
| 344 | 0, &vertices, NULL); |
reed | e4ef1ca | 2015-02-17 18:38:38 -0800 | [diff] [blame] | 345 | SkASSERT(fCachedGeometryProcessor->getVertexStride() == 2 * sizeof(SkPoint)); |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 346 | GrAlwaysAssert(success); |
| 347 | |
| 348 | SkScalar dx = pathData->fBounds.fLeft; |
| 349 | SkScalar dy = pathData->fBounds.fTop; |
reed | e4ef1ca | 2015-02-17 18:38:38 -0800 | [diff] [blame] | 350 | SkScalar width = pathData->fBounds.width(); |
| 351 | SkScalar height = pathData->fBounds.height(); |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 352 | |
jvanverth | b61283f | 2014-10-30 05:57:21 -0700 | [diff] [blame] | 353 | SkScalar invScale = 1.0f/pathData->fScale; |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 354 | dx *= invScale; |
| 355 | dy *= invScale; |
| 356 | width *= invScale; |
| 357 | height *= invScale; |
reed | e4ef1ca | 2015-02-17 18:38:38 -0800 | [diff] [blame] | 358 | |
| 359 | SkFixed tx = SkIntToFixed(pathData->fAtlasLocation.fX); |
| 360 | SkFixed ty = SkIntToFixed(pathData->fAtlasLocation.fY); |
| 361 | SkFixed tw = SkScalarToFixed(pathData->fBounds.width()); |
| 362 | SkFixed th = SkScalarToFixed(pathData->fBounds.height()); |
| 363 | |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 364 | // vertex positions |
| 365 | SkRect r = SkRect::MakeXYWH(dx, dy, width, height); |
reed | e4ef1ca | 2015-02-17 18:38:38 -0800 | [diff] [blame] | 366 | size_t vertSize = 2 * sizeof(SkPoint); |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 367 | SkPoint* positions = reinterpret_cast<SkPoint*>(vertices); |
| 368 | positions->setRectFan(r.left(), r.top(), r.right(), r.bottom(), vertSize); |
| 369 | |
| 370 | // vertex texture coords |
reed | e4ef1ca | 2015-02-17 18:38:38 -0800 | [diff] [blame] | 371 | intptr_t intPtr = reinterpret_cast<intptr_t>(positions); |
| 372 | SkPoint* textureCoords = reinterpret_cast<SkPoint*>(intPtr + vertSize - sizeof(SkPoint)); |
| 373 | textureCoords->setRectFan(SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx)), |
| 374 | SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty)), |
| 375 | SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx + tw)), |
| 376 | SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty + th)), |
| 377 | vertSize); |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 378 | |
joshualitt | 8059eb9 | 2014-12-29 15:10:07 -0800 | [diff] [blame] | 379 | viewMatrix.mapRect(&r); |
jvanverth | 6d22eca | 2014-10-28 11:10:48 -0700 | [diff] [blame] | 380 | target->setIndexSourceToBuffer(fContext->getQuadIndexBuffer()); |
egdaniel | 8dd688b | 2015-01-22 10:16:09 -0800 | [diff] [blame] | 381 | target->drawIndexedInstances(pipelineBuilder, fCachedGeometryProcessor.get(), |
joshualitt | 56995b5 | 2014-12-11 15:44:02 -0800 | [diff] [blame] | 382 | kTriangles_GrPrimitiveType, 1, 4, 6, &r); |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 383 | target->resetVertexSource(); |
jvanverth | fa38a30 | 2014-10-06 05:59:05 -0700 | [diff] [blame] | 384 | |
| 385 | return true; |
| 386 | } |
| 387 | |