Chromium Code Reviews| OLD | NEW |
|---|---|
| (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 | |
|
robertphillips
2014/09/26 14:00:30
Is it kosher to include a gl header in gpu?
bsalomon
2014/09/26 17:32:51
We do this for processors all over the place, othe
jvanverth1
2014/10/03 17:28:21
Removed anyway, it's not needed.
| |
| 9 #include "gl/builders/GrGLProgramBuilder.h" | |
| 10 #include "GrAADistanceFieldPathRenderer.h" | |
| 11 | |
| 12 #include "GrAtlas.h" | |
| 13 #include "GrContext.h" | |
| 14 #include "GrDrawState.h" | |
| 15 #include "GrSWMaskHelper.h" | |
| 16 #include "effects/GrDistanceFieldTextureEffect.h" | |
| 17 | |
| 18 #include "SkDistanceFieldGen.h" | |
| 19 #include "SkRTConf.h" | |
| 20 | |
| 21 #define GR_ATLAS_TEXTURE_WIDTH 1024 | |
|
bsalomon
2014/09/26 17:32:51
Let's drop the GR_ prefix on these macros. They do
jvanverth1
2014/10/03 17:28:21
Done.
| |
| 22 #define GR_ATLAS_TEXTURE_HEIGHT 1024 | |
| 23 | |
| 24 #define GR_PLOT_WIDTH 256 | |
| 25 #define GR_PLOT_HEIGHT 256 | |
| 26 | |
| 27 #define GR_NUM_PLOTS_X (GR_ATLAS_TEXTURE_WIDTH / GR_PLOT_WIDTH) | |
| 28 #define GR_NUM_PLOTS_Y (GR_ATLAS_TEXTURE_HEIGHT / GR_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 | |
| 33 //////////////////////////////////////////////////////////////////////////////// | |
| 34 GrAADistanceFieldPathRenderer::~GrAADistanceFieldPathRenderer() { | |
| 35 PathDataList::Iter iter; | |
| 36 iter.init(fPathList, PathDataList::Iter::kHead_IterStart); | |
| 37 PathData* pathData; | |
| 38 while ((pathData = iter.get())) { | |
| 39 iter.next(); | |
| 40 fPathList.remove(pathData); | |
|
robertphillips
2014/09/26 14:00:29
SkDELETE
jvanverth1
2014/10/03 17:28:23
Done.
| |
| 41 delete pathData; | |
| 42 } | |
| 43 | |
|
robertphillips
2014/09/26 14:00:30
SkDELETE
jvanverth1
2014/10/03 17:28:23
Done.
| |
| 44 delete fAtlas; | |
| 45 } | |
| 46 | |
| 47 //////////////////////////////////////////////////////////////////////////////// | |
| 48 bool GrAADistanceFieldPathRenderer::canDrawPath(const SkPath& path, | |
|
robertphillips
2014/09/26 14:00:29
make these line up?
jvanverth1
2014/10/03 17:28:22
Done.
| |
| 49 const SkStrokeRec& stroke, | |
| 50 const GrDrawTarget* target, | |
| 51 bool antiAlias) const { | |
| 52 // TODO: Support inverse fill | |
|
bsalomon
2014/09/26 17:32:51
You might want to check out the GrGLPath stuff...
jvanverth1
2014/10/03 17:28:22
Acknowledged.
| |
| 53 // TODO: Support strokes | |
| 54 if (!target->caps()->shaderDerivativeSupport() || !antiAlias || path.isInver seFillType() | |
| 55 || SkStrokeRec::kFill_Style != stroke.getStyle()) { | |
| 56 return false; | |
| 57 } | |
| 58 | |
|
robertphillips
2014/09/26 14:00:30
3x ?
jvanverth1
2014/10/03 17:28:21
Done.
| |
| 59 // currently don't support scaling more than 4x | |
|
egdaniel
2014/09/26 13:30:25
But check is on for max scale of 3?
jvanverth1
2014/10/03 17:28:21
Done.
| |
| 60 const GrDrawState& drawState = target->getDrawState(); | |
| 61 const SkMatrix& vm = drawState.getViewMatrix(); | |
| 62 if (vm.getMaxScale() > 3.0f) { | |
| 63 return false; | |
| 64 } | |
| 65 | |
| 66 // only support paths smaller than 64 x 64 | |
| 67 const SkRect& bounds = path.getBounds(); | |
| 68 return bounds.width() < 64.f && bounds.height() < 64.f; | |
| 69 } | |
| 70 | |
| 71 | |
| 72 //*** not sure if this is needed | |
|
bsalomon
2014/09/26 17:32:51
I think it's not, but we should have a GM that cli
jvanverth1
2014/10/03 17:28:22
I think it is needed -- GrSoftwarePathRenderer has
| |
| 73 GrPathRenderer::StencilSupport GrAADistanceFieldPathRenderer::onGetStencilSuppor t( | |
| 74 const Sk Path&, | |
| 75 const Sk StrokeRec&, | |
| 76 const Gr DrawTarget*) 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, | |
|
robertphillips
2014/09/26 14:00:29
line these up?
jvanverth1
2014/10/03 17:28:22
Done.
| |
| 90 const SkStrokeRec& stroke, | |
| 91 GrDrawTarget* target, | |
| 92 bool antiAlias) { | |
| 93 if (path.isEmpty()) { | |
|
bsalomon
2014/09/26 17:32:51
maybe a comment that we already bailed on inverse
jvanverth1
2014/10/03 17:28:21
Done.
| |
| 94 return true; | |
| 95 } | |
| 96 | |
| 97 if (NULL == fContext) { | |
|
bsalomon
2014/09/26 17:32:51
Do we need this?
jvanverth1
2014/10/03 17:28:22
Done.
| |
| 98 return false; | |
| 99 } | |
| 100 | |
| 101 // check to see if path is cached | |
| 102 // TODO: handle stroked vs. filled version of same path | |
| 103 PathData* pathData = fPathCache.find(path.getGenerationID()); | |
| 104 if (NULL == pathData) { | |
|
robertphillips
2014/09/26 14:00:29
this-> ?
jvanverth1
2014/10/03 17:28:21
Done.
| |
| 105 pathData = addPathToAtlas(path, stroke, antiAlias); | |
| 106 if (NULL == pathData) { | |
| 107 return false; | |
| 108 } | |
| 109 } | |
| 110 | |
| 111 // use signed distance field to render | |
|
robertphillips
2014/09/26 14:00:29
this-> ?
jvanverth1
2014/10/03 17:28:22
Done.
| |
| 112 return internalDrawPath(path, pathData, target); | |
| 113 } | |
| 114 | |
|
robertphillips
2014/09/26 14:00:30
// This is the factor by which we scale the path p
jvanverth1
2014/10/03 17:28:21
Done.
| |
| 115 const SkScalar kScaleFactor = 2.0f; | |
| 116 const SkScalar kAntiAliasPad = 1.0f; | |
| 117 | |
| 118 GrAADistanceFieldPathRenderer::PathData* GrAADistanceFieldPathRenderer::addPathT oAtlas( | |
| 119 const Sk Path& path, | |
| 120 const Sk StrokeRec& stroke, | |
| 121 bool ant iAlias) { | |
| 122 // generate distance field and add to atlas | |
| 123 if (NULL == fAtlas) { | |
| 124 SkISize textureSize = SkISize::Make(GR_ATLAS_TEXTURE_WIDTH, | |
| 125 GR_ATLAS_TEXTURE_HEIGHT); | |
| 126 fAtlas = SkNEW_ARGS(GrAtlas, (fContext->getGpu(), kAlpha_8_GrPixelConfig , | |
| 127 kNone_GrTextureFlags, textureSize, | |
| 128 GR_NUM_PLOTS_X, GR_NUM_PLOTS_Y, false)); | |
| 129 if (NULL == fAtlas) { | |
| 130 return NULL; | |
| 131 } | |
| 132 } | |
| 133 | |
| 134 const SkRect& bounds = path.getBounds(); | |
| 135 | |
| 136 // generate bounding rect for bitmap draw | |
| 137 SkRect scaledBounds = bounds; | |
| 138 // scale up by 2x | |
| 139 scaledBounds.fLeft *= kScaleFactor; | |
| 140 scaledBounds.fTop *= kScaleFactor; | |
| 141 scaledBounds.fRight *= kScaleFactor; | |
| 142 scaledBounds.fBottom *= kScaleFactor; | |
| 143 // move the origin to an integer boundary (gives better results) | |
| 144 SkScalar dx = SkScalarFraction(scaledBounds.fLeft); | |
| 145 SkScalar dy = SkScalarFraction(scaledBounds.fTop); | |
| 146 scaledBounds.offset(-dx, -dy); | |
| 147 // get integer boundary | |
| 148 SkIRect devPathBounds; | |
| 149 scaledBounds.roundOut(&devPathBounds); | |
| 150 // pad by 1 to allow room for antialiasing | |
|
robertphillips
2014/09/26 14:00:30
Not CeilToInt ?
jvanverth1
2014/10/03 17:28:21
Done.
| |
| 151 devPathBounds.outset(SkScalarFloorToInt(kAntiAliasPad), SkScalarFloorToInt(k AntiAliasPad)); | |
| 152 // move origin to upper left corner | |
| 153 devPathBounds.offsetTo(0,0); | |
| 154 | |
| 155 // draw path to bitmap | |
| 156 SkMatrix drawMatrix; | |
| 157 drawMatrix.setTranslate(-bounds.left(), -bounds.top()); | |
| 158 drawMatrix.postScale(kScaleFactor, kScaleFactor); | |
| 159 drawMatrix.postTranslate(kAntiAliasPad, kAntiAliasPad); | |
| 160 GrSWMaskHelper helper(fContext); | |
| 161 | |
| 162 if (!helper.init(devPathBounds, &drawMatrix)) { | |
| 163 return NULL; | |
| 164 } | |
| 165 helper.draw(path, stroke, SkRegion::kReplace_Op, antiAlias, 0xFF); | |
| 166 | |
| 167 // generate signed distance field | |
| 168 devPathBounds.outset(SK_DistanceFieldPad, SK_DistanceFieldPad); | |
| 169 int width = devPathBounds.width(); | |
| 170 int height = devPathBounds.height(); | |
| 171 SkAutoSMalloc<1024> dfStorage(width*height*sizeof(unsigned char)); | |
| 172 helper.toSDF(dfStorage.get()); | |
| 173 | |
| 174 // add to atlas | |
| 175 SkIPoint16 atlasLocation; | |
| 176 GrPlot* plot = fAtlas->addToAtlas(&fPlotUsage, width, height, dfStorage.get( ), | |
| 177 &atlasLocation); | |
| 178 | |
| 179 // if atlas full | |
| 180 if (NULL == plot) { | |
|
robertphillips
2014/09/26 14:00:29
this-> ?
jvanverth1
2014/10/03 17:28:21
Done.
| |
| 181 if (freeUnusedPlot()) { | |
| 182 plot = fAtlas->addToAtlas(&fPlotUsage, width, height, dfStorage.get( ), | |
| 183 &atlasLocation); | |
| 184 if (plot) { | |
| 185 goto HAS_ATLAS; | |
| 186 } | |
| 187 } | |
| 188 | |
| 189 if (c_DumpPathCache) { | |
| 190 #ifdef SK_DEVELOPER | |
| 191 GrTexture* texture = fAtlas->getTexture(); | |
| 192 texture->savePixels("pathcache.png"); | |
| 193 #endif | |
| 194 } | |
| 195 | |
| 196 // before we purge the cache, we must flush any accumulated draws | |
| 197 fContext->flush(); | |
| 198 | |
|
robertphillips
2014/09/26 14:00:29
this-> ?
jvanverth1
2014/10/03 17:28:21
Done.
| |
| 199 if (freeUnusedPlot()) { | |
| 200 plot = fAtlas->addToAtlas(&fPlotUsage, width, height, dfStorage.get( ), | |
| 201 &atlasLocation); | |
| 202 if (plot) { | |
| 203 goto HAS_ATLAS; | |
| 204 } | |
| 205 } | |
| 206 | |
| 207 return NULL; | |
| 208 } | |
| 209 | |
| 210 HAS_ATLAS: | |
|
robertphillips
2014/09/26 14:00:29
Guard this ?!
jvanverth1
2014/10/03 17:28:22
Whoops, removed.
| |
| 211 GrTexture* texture = fAtlas->getTexture(); | |
| 212 texture->savePixels("pathcache.png"); | |
| 213 | |
| 214 // add to cache | |
|
robertphillips
2014/09/26 14:00:29
SkNEW ?
jvanverth1
2014/10/03 17:28:22
Done.
| |
| 215 PathData* pathData = new PathData(); | |
| 216 pathData->fGenID = path.getGenerationID(); | |
| 217 pathData->fPlot = plot; | |
| 218 // change the scaled rect to match the size of the inset distance field | |
| 219 scaledBounds.fRight = scaledBounds.fLeft + | |
| 220 SkIntToScalar(devPathBounds.width() - 2*SK_DistanceFieldInset); | |
| 221 scaledBounds.fBottom = scaledBounds.fTop + | |
| 222 SkIntToScalar(devPathBounds.height() - 2*SK_DistanceFieldInset); | |
| 223 // shift the origin to the correct place relative to the distance field | |
| 224 // need to also restore the fractional translation | |
| 225 scaledBounds.offset(-SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPad + dx, | |
| 226 -SkIntToScalar(SK_DistanceFieldInset) - kAntiAliasPad + dy); | |
| 227 pathData->fBounds = scaledBounds; | |
| 228 // origin we render from is inset from distance field edge | |
| 229 atlasLocation.fX += SK_DistanceFieldInset; | |
| 230 atlasLocation.fY += SK_DistanceFieldInset; | |
| 231 pathData->fAtlasLocation = atlasLocation; | |
| 232 | |
| 233 fPathCache.add(pathData); | |
| 234 fPathList.addToTail(pathData); | |
| 235 | |
| 236 return pathData; | |
| 237 } | |
| 238 | |
| 239 bool GrAADistanceFieldPathRenderer::freeUnusedPlot() { | |
| 240 // find an unused plot | |
|
robertphillips
2014/09/26 14:00:30
I don't think this fAtlas alias buys us much.
jvanverth1
2014/10/03 17:28:21
Done.
| |
| 241 GrAtlas* atlas = fAtlas; | |
| 242 GrPlot* plot = atlas->getUnusedPlot(); | |
| 243 if (NULL == plot) { | |
| 244 return false; | |
| 245 } | |
| 246 plot->resetRects(); | |
| 247 | |
| 248 // remove any paths that use this plot | |
| 249 PathDataList::Iter iter; | |
| 250 iter.init(fPathList, PathDataList::Iter::kHead_IterStart); | |
| 251 PathData* pathData; | |
| 252 while ((pathData = iter.get())) { | |
| 253 iter.next(); | |
| 254 if (plot == pathData->fPlot) { | |
| 255 fPathCache.remove(pathData->fGenID); | |
| 256 fPathList.remove(pathData); | |
|
robertphillips
2014/09/26 14:00:29
SkDELETE ?
jvanverth1
2014/10/03 17:28:23
Done.
| |
| 257 delete pathData; | |
| 258 } | |
| 259 } | |
| 260 | |
| 261 // tell the atlas to free the plot | |
| 262 GrAtlas::RemovePlot(&fPlotUsage, plot); | |
| 263 | |
| 264 return true; | |
| 265 } | |
| 266 | |
| 267 bool GrAADistanceFieldPathRenderer::internalDrawPath(const SkPath& path, | |
|
robertphillips
2014/09/26 14:00:29
line these up ?
jvanverth1
2014/10/03 17:28:21
Done.
| |
| 268 const PathData* pathData, | |
| 269 GrDrawTarget* target) { | |
| 270 | |
| 271 GrTexture* texture = fAtlas->getTexture(); | |
| 272 GrDrawState* drawState = target->drawState(); | |
| 273 | |
| 274 SkASSERT(pathData->fPlot); | |
| 275 GrDrawTarget::DrawToken drawToken = target->getCurrentDrawToken(); | |
| 276 pathData->fPlot->setDrawToken(drawToken); | |
| 277 | |
| 278 // make me some vertices | |
| 279 drawState->setVertexAttribs<gSDFPathVertexAttribs>(SK_ARRAY_COUNT(gSDFPathVe rtexAttribs), | |
| 280 kSDFPathVASize); | |
| 281 void* vertices = NULL; | |
| 282 void* indices = NULL; | |
|
robertphillips
2014/09/26 14:00:28
Will this fit on one line ?
jvanverth1
2014/10/03 17:28:21
Done.
| |
| 283 bool success = target->reserveVertexAndIndexSpace(4, | |
| 284 6, | |
| 285 &vertices, | |
| 286 &indices); | |
| 287 GrAlwaysAssert(success); | |
| 288 | |
| 289 SkScalar dx = pathData->fBounds.fLeft; | |
| 290 SkScalar dy = pathData->fBounds.fTop; | |
| 291 SkScalar width = pathData->fBounds.width(); | |
| 292 SkScalar height = pathData->fBounds.height(); | |
| 293 | |
|
robertphillips
2014/09/26 14:00:29
invScale ?
jvanverth1
2014/10/03 17:28:22
Done.
| |
| 294 SkScalar scale = 1.0f/kScaleFactor; | |
| 295 dx *= scale; | |
| 296 dy *= scale; | |
| 297 width *= scale; | |
| 298 height *= scale; | |
| 299 | |
| 300 SkFixed tx = SkIntToFixed(pathData->fAtlasLocation.fX); | |
| 301 SkFixed ty = SkIntToFixed(pathData->fAtlasLocation.fY); | |
| 302 SkFixed tw = SkScalarToFixed(pathData->fBounds.width()); | |
| 303 SkFixed th = SkScalarToFixed(pathData->fBounds.height()); | |
| 304 | |
|
robertphillips
2014/09/26 14:00:29
SkRect::MakeWH(dx, dy, width, height); ?
jvanverth1
2014/10/03 17:28:22
Done.
| |
| 305 SkRect r; | |
| 306 r.fLeft = dx; | |
| 307 r.fTop = dy; | |
| 308 r.fRight = dx + width; | |
| 309 r.fBottom = dy + height; | |
| 310 | |
| 311 size_t vertSize = 2 * sizeof(SkPoint); | |
| 312 | |
| 313 SkPoint* positions = reinterpret_cast<SkPoint*>(vertices); | |
| 314 positions->setRectFan(r.left(), r.top(), r.right(), r.bottom(), vertSize); | |
| 315 | |
| 316 // The texture coords are last in both the with and without color vertex lay outs. | |
| 317 SkPoint* textureCoords = reinterpret_cast<SkPoint*>( | |
|
robertphillips
2014/09/26 14:00:29
overlength.
jvanverth1
2014/10/03 17:28:22
Done.
| |
| 318 reinterpret_cast<intptr_ t>(positions)+vertSize - sizeof(SkPoint)); | |
|
egdaniel
2014/09/26 13:30:25
fix line wrap
jvanverth1
2014/10/03 17:28:22
Done.
| |
| 319 textureCoords->setRectFan(SkFixedToFloat(texture->normalizeFixedX(tx)), | |
| 320 SkFixedToFloat(texture->normalizeFixedY(ty)), | |
| 321 SkFixedToFloat(texture->normalizeFixedX(tx + tw)), | |
| 322 SkFixedToFloat(texture->normalizeFixedY(ty + th)), | |
| 323 vertSize); | |
| 324 | |
| 325 uint16_t* indexPtr = reinterpret_cast<uint16_t*>(indices); | |
| 326 *indexPtr++ = 0; | |
| 327 *indexPtr++ = 1; | |
| 328 *indexPtr++ = 2; | |
| 329 *indexPtr++ = 0; | |
| 330 *indexPtr++ = 2; | |
| 331 *indexPtr++ = 3; | |
| 332 | |
| 333 // set up any flags | |
| 334 uint32_t flags = 0; | |
| 335 const SkMatrix& vm = drawState->getViewMatrix(); | |
| 336 flags |= vm.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0; | |
| 337 | |
| 338 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_ FilterMode); | |
| 339 drawState->setGeometryProcessor(GrDistanceFieldNoGammaTextureEffect::Create( texture, | |
| 340 params, | |
| 341 flags))->unref(); | |
| 342 | |
|
robertphillips
2014/09/26 14:00:29
one line ?
jvanverth1
2014/10/03 17:28:22
Done.
| |
| 343 target->drawIndexedInstances(kTriangles_GrPrimitiveType, | |
| 344 1, | |
| 345 4, 6, &r); | |
| 346 target->resetVertexSource(); | |
| 347 target->resetIndexSource(); | |
| 348 | |
| 349 return true; | |
| 350 } | |
| 351 | |
| OLD | NEW |