GrSmallPathRenderer.cpp 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994
  1. /*
  2. * Copyright 2014 Google Inc.
  3. * Copyright 2017 ARM Ltd.
  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. #include "src/gpu/ops/GrSmallPathRenderer.h"
  9. #include "include/core/SkPaint.h"
  10. #include "src/core/SkAutoMalloc.h"
  11. #include "src/core/SkAutoPixmapStorage.h"
  12. #include "src/core/SkDistanceFieldGen.h"
  13. #include "src/core/SkDraw.h"
  14. #include "src/core/SkPointPriv.h"
  15. #include "src/core/SkRasterClip.h"
  16. #include "src/gpu/GrAuditTrail.h"
  17. #include "src/gpu/GrBuffer.h"
  18. #include "src/gpu/GrCaps.h"
  19. #include "src/gpu/GrDistanceFieldGenFromVector.h"
  20. #include "src/gpu/GrDrawOpTest.h"
  21. #include "src/gpu/GrRenderTargetContext.h"
  22. #include "src/gpu/GrResourceProvider.h"
  23. #include "src/gpu/GrVertexWriter.h"
  24. #include "src/gpu/effects/GrBitmapTextGeoProc.h"
  25. #include "src/gpu/effects/GrDistanceFieldGeoProc.h"
  26. #include "src/gpu/geometry/GrQuad.h"
  27. #include "src/gpu/ops/GrMeshDrawOp.h"
  28. #include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
  29. #define ATLAS_TEXTURE_WIDTH 2048
  30. #define ATLAS_TEXTURE_HEIGHT 2048
  31. #define PLOT_WIDTH 512
  32. #define PLOT_HEIGHT 256
  33. #define NUM_PLOTS_X (ATLAS_TEXTURE_WIDTH / PLOT_WIDTH)
  34. #define NUM_PLOTS_Y (ATLAS_TEXTURE_HEIGHT / PLOT_HEIGHT)
  35. #ifdef DF_PATH_TRACKING
  36. static int g_NumCachedShapes = 0;
  37. static int g_NumFreedShapes = 0;
  38. #endif
  39. // mip levels
  40. static const SkScalar kIdealMinMIP = 12;
  41. static const SkScalar kMaxMIP = 162;
  42. static const SkScalar kMaxDim = 73;
  43. static const SkScalar kMinSize = SK_ScalarHalf;
  44. static const SkScalar kMaxSize = 2*kMaxMIP;
  45. class ShapeDataKey {
  46. public:
  47. ShapeDataKey() {}
  48. ShapeDataKey(const ShapeDataKey& that) { *this = that; }
  49. ShapeDataKey(const GrShape& shape, uint32_t dim) { this->set(shape, dim); }
  50. ShapeDataKey(const GrShape& shape, const SkMatrix& ctm) { this->set(shape, ctm); }
  51. ShapeDataKey& operator=(const ShapeDataKey& that) {
  52. fKey.reset(that.fKey.count());
  53. memcpy(fKey.get(), that.fKey.get(), fKey.count() * sizeof(uint32_t));
  54. return *this;
  55. }
  56. // for SDF paths
  57. void set(const GrShape& shape, uint32_t dim) {
  58. // Shapes' keys are for their pre-style geometry, but by now we shouldn't have any
  59. // relevant styling information.
  60. SkASSERT(shape.style().isSimpleFill());
  61. SkASSERT(shape.hasUnstyledKey());
  62. int shapeKeySize = shape.unstyledKeySize();
  63. fKey.reset(1 + shapeKeySize);
  64. fKey[0] = dim;
  65. shape.writeUnstyledKey(&fKey[1]);
  66. }
  67. // for bitmap paths
  68. void set(const GrShape& shape, const SkMatrix& ctm) {
  69. // Shapes' keys are for their pre-style geometry, but by now we shouldn't have any
  70. // relevant styling information.
  71. SkASSERT(shape.style().isSimpleFill());
  72. SkASSERT(shape.hasUnstyledKey());
  73. // We require the upper left 2x2 of the matrix to match exactly for a cache hit.
  74. SkScalar sx = ctm.get(SkMatrix::kMScaleX);
  75. SkScalar sy = ctm.get(SkMatrix::kMScaleY);
  76. SkScalar kx = ctm.get(SkMatrix::kMSkewX);
  77. SkScalar ky = ctm.get(SkMatrix::kMSkewY);
  78. SkScalar tx = ctm.get(SkMatrix::kMTransX);
  79. SkScalar ty = ctm.get(SkMatrix::kMTransY);
  80. // Allow 8 bits each in x and y of subpixel positioning.
  81. tx -= SkScalarFloorToScalar(tx);
  82. ty -= SkScalarFloorToScalar(ty);
  83. SkFixed fracX = SkScalarToFixed(tx) & 0x0000FF00;
  84. SkFixed fracY = SkScalarToFixed(ty) & 0x0000FF00;
  85. int shapeKeySize = shape.unstyledKeySize();
  86. fKey.reset(5 + shapeKeySize);
  87. fKey[0] = SkFloat2Bits(sx);
  88. fKey[1] = SkFloat2Bits(sy);
  89. fKey[2] = SkFloat2Bits(kx);
  90. fKey[3] = SkFloat2Bits(ky);
  91. fKey[4] = fracX | (fracY >> 8);
  92. shape.writeUnstyledKey(&fKey[5]);
  93. }
  94. bool operator==(const ShapeDataKey& that) const {
  95. return fKey.count() == that.fKey.count() &&
  96. 0 == memcmp(fKey.get(), that.fKey.get(), sizeof(uint32_t) * fKey.count());
  97. }
  98. int count32() const { return fKey.count(); }
  99. const uint32_t* data() const { return fKey.get(); }
  100. private:
  101. // The key is composed of the GrShape's key, and either the dimensions of the DF
  102. // generated for the path (32x32 max, 64x64 max, 128x128 max) if an SDF image or
  103. // the matrix for the path with only fractional translation.
  104. SkAutoSTArray<24, uint32_t> fKey;
  105. };
  106. class ShapeData {
  107. public:
  108. ShapeDataKey fKey;
  109. GrDrawOpAtlas::AtlasID fID;
  110. SkRect fBounds;
  111. GrIRect16 fTextureCoords;
  112. SK_DECLARE_INTERNAL_LLIST_INTERFACE(ShapeData);
  113. static inline const ShapeDataKey& GetKey(const ShapeData& data) {
  114. return data.fKey;
  115. }
  116. static inline uint32_t Hash(const ShapeDataKey& key) {
  117. return SkOpts::hash(key.data(), sizeof(uint32_t) * key.count32());
  118. }
  119. };
  120. // Callback to clear out internal path cache when eviction occurs
  121. void GrSmallPathRenderer::HandleEviction(GrDrawOpAtlas::AtlasID id, void* pr) {
  122. GrSmallPathRenderer* dfpr = (GrSmallPathRenderer*)pr;
  123. // remove any paths that use this plot
  124. ShapeDataList::Iter iter;
  125. iter.init(dfpr->fShapeList, ShapeDataList::Iter::kHead_IterStart);
  126. ShapeData* shapeData;
  127. while ((shapeData = iter.get())) {
  128. iter.next();
  129. if (id == shapeData->fID) {
  130. dfpr->fShapeCache.remove(shapeData->fKey);
  131. dfpr->fShapeList.remove(shapeData);
  132. delete shapeData;
  133. #ifdef DF_PATH_TRACKING
  134. ++g_NumFreedPaths;
  135. #endif
  136. }
  137. }
  138. }
  139. ////////////////////////////////////////////////////////////////////////////////
  140. GrSmallPathRenderer::GrSmallPathRenderer() : fAtlas(nullptr) {}
  141. GrSmallPathRenderer::~GrSmallPathRenderer() {
  142. ShapeDataList::Iter iter;
  143. iter.init(fShapeList, ShapeDataList::Iter::kHead_IterStart);
  144. ShapeData* shapeData;
  145. while ((shapeData = iter.get())) {
  146. iter.next();
  147. delete shapeData;
  148. }
  149. #ifdef DF_PATH_TRACKING
  150. SkDebugf("Cached shapes: %d, freed shapes: %d\n", g_NumCachedShapes, g_NumFreedShapes);
  151. #endif
  152. }
  153. ////////////////////////////////////////////////////////////////////////////////
  154. GrPathRenderer::CanDrawPath GrSmallPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
  155. if (!args.fCaps->shaderCaps()->shaderDerivativeSupport()) {
  156. return CanDrawPath::kNo;
  157. }
  158. // If the shape has no key then we won't get any reuse.
  159. if (!args.fShape->hasUnstyledKey()) {
  160. return CanDrawPath::kNo;
  161. }
  162. // This only supports filled paths, however, the caller may apply the style to make a filled
  163. // path and try again.
  164. if (!args.fShape->style().isSimpleFill()) {
  165. return CanDrawPath::kNo;
  166. }
  167. // This does non-inverse coverage-based antialiased fills.
  168. if (GrAAType::kCoverage != args.fAAType) {
  169. return CanDrawPath::kNo;
  170. }
  171. // TODO: Support inverse fill
  172. if (args.fShape->inverseFilled()) {
  173. return CanDrawPath::kNo;
  174. }
  175. // Only support paths with bounds within kMaxDim by kMaxDim,
  176. // scaled to have bounds within kMaxSize by kMaxSize.
  177. // The goal is to accelerate rendering of lots of small paths that may be scaling.
  178. SkScalar scaleFactors[2] = { 1, 1 };
  179. if (!args.fViewMatrix->hasPerspective() && !args.fViewMatrix->getMinMaxScales(scaleFactors)) {
  180. return CanDrawPath::kNo;
  181. }
  182. SkRect bounds = args.fShape->styledBounds();
  183. SkScalar minDim = SkMinScalar(bounds.width(), bounds.height());
  184. SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height());
  185. SkScalar minSize = minDim * SkScalarAbs(scaleFactors[0]);
  186. SkScalar maxSize = maxDim * SkScalarAbs(scaleFactors[1]);
  187. if (maxDim > kMaxDim || kMinSize > minSize || maxSize > kMaxSize) {
  188. return CanDrawPath::kNo;
  189. }
  190. return CanDrawPath::kYes;
  191. }
  192. ////////////////////////////////////////////////////////////////////////////////
  193. // padding around path bounds to allow for antialiased pixels
  194. static const SkScalar kAntiAliasPad = 1.0f;
  195. class GrSmallPathRenderer::SmallPathOp final : public GrMeshDrawOp {
  196. private:
  197. using Helper = GrSimpleMeshDrawOpHelperWithStencil;
  198. public:
  199. DEFINE_OP_CLASS_ID
  200. using ShapeCache = SkTDynamicHash<ShapeData, ShapeDataKey>;
  201. using ShapeDataList = GrSmallPathRenderer::ShapeDataList;
  202. static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
  203. GrPaint&& paint,
  204. const GrShape& shape,
  205. const SkMatrix& viewMatrix,
  206. GrDrawOpAtlas* atlas,
  207. ShapeCache* shapeCache,
  208. ShapeDataList* shapeList,
  209. bool gammaCorrect,
  210. const GrUserStencilSettings* stencilSettings) {
  211. return Helper::FactoryHelper<SmallPathOp>(context, std::move(paint), shape, viewMatrix,
  212. atlas, shapeCache, shapeList, gammaCorrect,
  213. stencilSettings);
  214. }
  215. SmallPathOp(Helper::MakeArgs helperArgs, const SkPMColor4f& color, const GrShape& shape,
  216. const SkMatrix& viewMatrix, GrDrawOpAtlas* atlas, ShapeCache* shapeCache,
  217. ShapeDataList* shapeList, bool gammaCorrect,
  218. const GrUserStencilSettings* stencilSettings)
  219. : INHERITED(ClassID()), fHelper(helperArgs, GrAAType::kCoverage, stencilSettings) {
  220. SkASSERT(shape.hasUnstyledKey());
  221. // Compute bounds
  222. this->setTransformedBounds(shape.bounds(), viewMatrix, HasAABloat::kYes, IsZeroArea::kNo);
  223. #if defined(SK_BUILD_FOR_ANDROID) && !defined(SK_BUILD_FOR_ANDROID_FRAMEWORK)
  224. fUsesDistanceField = true;
  225. #else
  226. // only use distance fields on desktop and Android framework to save space in the atlas
  227. fUsesDistanceField = this->bounds().width() > kMaxMIP || this->bounds().height() > kMaxMIP;
  228. #endif
  229. // always use distance fields if in perspective
  230. fUsesDistanceField = fUsesDistanceField || viewMatrix.hasPerspective();
  231. fShapes.emplace_back(Entry{color, shape, viewMatrix});
  232. fAtlas = atlas;
  233. fShapeCache = shapeCache;
  234. fShapeList = shapeList;
  235. fGammaCorrect = gammaCorrect;
  236. }
  237. const char* name() const override { return "SmallPathOp"; }
  238. void visitProxies(const VisitProxyFunc& func) const override {
  239. fHelper.visitProxies(func);
  240. const sk_sp<GrTextureProxy>* proxies = fAtlas->getProxies();
  241. for (uint32_t i = 0; i < fAtlas->numActivePages(); ++i) {
  242. SkASSERT(proxies[i]);
  243. func(proxies[i].get(), GrMipMapped::kNo);
  244. }
  245. }
  246. #ifdef SK_DEBUG
  247. SkString dumpInfo() const override {
  248. SkString string;
  249. for (const auto& geo : fShapes) {
  250. string.appendf("Color: 0x%08x\n", geo.fColor.toBytes_RGBA());
  251. }
  252. string += fHelper.dumpInfo();
  253. string += INHERITED::dumpInfo();
  254. return string;
  255. }
  256. #endif
  257. FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
  258. GrProcessorSet::Analysis finalize(
  259. const GrCaps& caps, const GrAppliedClip* clip, bool hasMixedSampledCoverage,
  260. GrClampType clampType) override {
  261. return fHelper.finalizeProcessors(
  262. caps, clip, hasMixedSampledCoverage, clampType,
  263. GrProcessorAnalysisCoverage::kSingleChannel, &fShapes.front().fColor, &fWideColor);
  264. }
  265. private:
  266. struct FlushInfo {
  267. sk_sp<const GrBuffer> fVertexBuffer;
  268. sk_sp<const GrBuffer> fIndexBuffer;
  269. sk_sp<GrGeometryProcessor> fGeometryProcessor;
  270. GrPipeline::FixedDynamicState* fFixedDynamicState;
  271. int fVertexOffset;
  272. int fInstancesToFlush;
  273. };
  274. void onPrepareDraws(Target* target) override {
  275. int instanceCount = fShapes.count();
  276. static constexpr int kMaxTextures = GrDistanceFieldPathGeoProc::kMaxTextures;
  277. GR_STATIC_ASSERT(GrBitmapTextGeoProc::kMaxTextures == kMaxTextures);
  278. FlushInfo flushInfo;
  279. flushInfo.fFixedDynamicState = target->makeFixedDynamicState(kMaxTextures);
  280. int numActiveProxies = fAtlas->numActivePages();
  281. const auto proxies = fAtlas->getProxies();
  282. for (int i = 0; i < numActiveProxies; ++i) {
  283. flushInfo.fFixedDynamicState->fPrimitiveProcessorTextures[i] = proxies[i].get();
  284. }
  285. // Setup GrGeometryProcessor
  286. const SkMatrix& ctm = fShapes[0].fViewMatrix;
  287. if (fUsesDistanceField) {
  288. uint32_t flags = 0;
  289. // Still need to key off of ctm to pick the right shader for the transformed quad
  290. flags |= ctm.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0;
  291. flags |= ctm.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
  292. flags |= fGammaCorrect ? kGammaCorrect_DistanceFieldEffectFlag : 0;
  293. const SkMatrix* matrix;
  294. SkMatrix invert;
  295. if (ctm.hasPerspective()) {
  296. matrix = &ctm;
  297. } else if (fHelper.usesLocalCoords()) {
  298. if (!ctm.invert(&invert)) {
  299. return;
  300. }
  301. matrix = &invert;
  302. } else {
  303. matrix = &SkMatrix::I();
  304. }
  305. flushInfo.fGeometryProcessor = GrDistanceFieldPathGeoProc::Make(
  306. *target->caps().shaderCaps(), *matrix, fWideColor, fAtlas->getProxies(),
  307. fAtlas->numActivePages(), GrSamplerState::ClampBilerp(), flags);
  308. } else {
  309. SkMatrix invert;
  310. if (fHelper.usesLocalCoords()) {
  311. if (!ctm.invert(&invert)) {
  312. return;
  313. }
  314. }
  315. flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make(
  316. *target->caps().shaderCaps(), this->color(), fWideColor, fAtlas->getProxies(),
  317. fAtlas->numActivePages(), GrSamplerState::ClampNearest(), kA8_GrMaskFormat,
  318. invert, false);
  319. }
  320. // allocate vertices
  321. const size_t kVertexStride = flushInfo.fGeometryProcessor->vertexStride();
  322. // We need to make sure we don't overflow a 32 bit int when we request space in the
  323. // makeVertexSpace call below.
  324. if (instanceCount > SK_MaxS32 / kVerticesPerQuad) {
  325. return;
  326. }
  327. GrVertexWriter vertices{target->makeVertexSpace(kVertexStride,
  328. kVerticesPerQuad * instanceCount,
  329. &flushInfo.fVertexBuffer,
  330. &flushInfo.fVertexOffset)};
  331. flushInfo.fIndexBuffer = target->resourceProvider()->refQuadIndexBuffer();
  332. if (!vertices.fPtr || !flushInfo.fIndexBuffer) {
  333. SkDebugf("Could not allocate vertices\n");
  334. return;
  335. }
  336. flushInfo.fInstancesToFlush = 0;
  337. for (int i = 0; i < instanceCount; i++) {
  338. const Entry& args = fShapes[i];
  339. ShapeData* shapeData;
  340. if (fUsesDistanceField) {
  341. // get mip level
  342. SkScalar maxScale;
  343. const SkRect& bounds = args.fShape.bounds();
  344. if (args.fViewMatrix.hasPerspective()) {
  345. // approximate the scale since we can't get it from the matrix
  346. SkRect xformedBounds;
  347. args.fViewMatrix.mapRect(&xformedBounds, bounds);
  348. maxScale = SkScalarAbs(SkTMax(xformedBounds.width() / bounds.width(),
  349. xformedBounds.height() / bounds.height()));
  350. } else {
  351. maxScale = SkScalarAbs(args.fViewMatrix.getMaxScale());
  352. }
  353. SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height());
  354. // We try to create the DF at a 2^n scaled path resolution (1/2, 1, 2, 4, etc.)
  355. // In the majority of cases this will yield a crisper rendering.
  356. SkScalar mipScale = 1.0f;
  357. // Our mipscale is the maxScale clamped to the next highest power of 2
  358. if (maxScale <= SK_ScalarHalf) {
  359. SkScalar log = SkScalarFloorToScalar(SkScalarLog2(SkScalarInvert(maxScale)));
  360. mipScale = SkScalarPow(2, -log);
  361. } else if (maxScale > SK_Scalar1) {
  362. SkScalar log = SkScalarCeilToScalar(SkScalarLog2(maxScale));
  363. mipScale = SkScalarPow(2, log);
  364. }
  365. SkASSERT(maxScale <= mipScale);
  366. SkScalar mipSize = mipScale*SkScalarAbs(maxDim);
  367. // For sizes less than kIdealMinMIP we want to use as large a distance field as we can
  368. // so we can preserve as much detail as possible. However, we can't scale down more
  369. // than a 1/4 of the size without artifacts. So the idea is that we pick the mipsize
  370. // just bigger than the ideal, and then scale down until we are no more than 4x the
  371. // original mipsize.
  372. if (mipSize < kIdealMinMIP) {
  373. SkScalar newMipSize = mipSize;
  374. do {
  375. newMipSize *= 2;
  376. } while (newMipSize < kIdealMinMIP);
  377. while (newMipSize > 4 * mipSize) {
  378. newMipSize *= 0.25f;
  379. }
  380. mipSize = newMipSize;
  381. }
  382. SkScalar desiredDimension = SkTMin(mipSize, kMaxMIP);
  383. // check to see if df path is cached
  384. ShapeDataKey key(args.fShape, SkScalarCeilToInt(desiredDimension));
  385. shapeData = fShapeCache->find(key);
  386. if (nullptr == shapeData || !fAtlas->hasID(shapeData->fID)) {
  387. // Remove the stale cache entry
  388. if (shapeData) {
  389. fShapeCache->remove(shapeData->fKey);
  390. fShapeList->remove(shapeData);
  391. delete shapeData;
  392. }
  393. SkScalar scale = desiredDimension / maxDim;
  394. shapeData = new ShapeData;
  395. if (!this->addDFPathToAtlas(target,
  396. &flushInfo,
  397. fAtlas,
  398. shapeData,
  399. args.fShape,
  400. SkScalarCeilToInt(desiredDimension),
  401. scale)) {
  402. delete shapeData;
  403. continue;
  404. }
  405. }
  406. } else {
  407. // check to see if bitmap path is cached
  408. ShapeDataKey key(args.fShape, args.fViewMatrix);
  409. shapeData = fShapeCache->find(key);
  410. if (nullptr == shapeData || !fAtlas->hasID(shapeData->fID)) {
  411. // Remove the stale cache entry
  412. if (shapeData) {
  413. fShapeCache->remove(shapeData->fKey);
  414. fShapeList->remove(shapeData);
  415. delete shapeData;
  416. }
  417. shapeData = new ShapeData;
  418. if (!this->addBMPathToAtlas(target,
  419. &flushInfo,
  420. fAtlas,
  421. shapeData,
  422. args.fShape,
  423. args.fViewMatrix)) {
  424. delete shapeData;
  425. continue;
  426. }
  427. }
  428. }
  429. auto uploadTarget = target->deferredUploadTarget();
  430. fAtlas->setLastUseToken(shapeData->fID, uploadTarget->tokenTracker()->nextDrawToken());
  431. this->writePathVertices(fAtlas, vertices, GrVertexColor(args.fColor, fWideColor),
  432. args.fViewMatrix, shapeData);
  433. flushInfo.fInstancesToFlush++;
  434. }
  435. this->flush(target, &flushInfo);
  436. }
  437. bool addToAtlas(GrMeshDrawOp::Target* target, FlushInfo* flushInfo, GrDrawOpAtlas* atlas,
  438. int width, int height, const void* image,
  439. GrDrawOpAtlas::AtlasID* id, SkIPoint16* atlasLocation) const {
  440. auto resourceProvider = target->resourceProvider();
  441. auto uploadTarget = target->deferredUploadTarget();
  442. GrDrawOpAtlas::ErrorCode code = atlas->addToAtlas(resourceProvider, id,
  443. uploadTarget, width, height,
  444. image, atlasLocation);
  445. if (GrDrawOpAtlas::ErrorCode::kError == code) {
  446. return false;
  447. }
  448. if (GrDrawOpAtlas::ErrorCode::kTryAgain == code) {
  449. this->flush(target, flushInfo);
  450. code = atlas->addToAtlas(resourceProvider, id, uploadTarget, width, height,
  451. image, atlasLocation);
  452. }
  453. return GrDrawOpAtlas::ErrorCode::kSucceeded == code;
  454. }
  455. bool addDFPathToAtlas(GrMeshDrawOp::Target* target, FlushInfo* flushInfo,
  456. GrDrawOpAtlas* atlas, ShapeData* shapeData, const GrShape& shape,
  457. uint32_t dimension, SkScalar scale) const {
  458. const SkRect& bounds = shape.bounds();
  459. // generate bounding rect for bitmap draw
  460. SkRect scaledBounds = bounds;
  461. // scale to mip level size
  462. scaledBounds.fLeft *= scale;
  463. scaledBounds.fTop *= scale;
  464. scaledBounds.fRight *= scale;
  465. scaledBounds.fBottom *= scale;
  466. // subtract out integer portion of origin
  467. // (SDF created will be placed with fractional offset burnt in)
  468. SkScalar dx = SkScalarFloorToScalar(scaledBounds.fLeft);
  469. SkScalar dy = SkScalarFloorToScalar(scaledBounds.fTop);
  470. scaledBounds.offset(-dx, -dy);
  471. // get integer boundary
  472. SkIRect devPathBounds;
  473. scaledBounds.roundOut(&devPathBounds);
  474. // pad to allow room for antialiasing
  475. const int intPad = SkScalarCeilToInt(kAntiAliasPad);
  476. // place devBounds at origin
  477. int width = devPathBounds.width() + 2*intPad;
  478. int height = devPathBounds.height() + 2*intPad;
  479. devPathBounds = SkIRect::MakeWH(width, height);
  480. SkScalar translateX = intPad - dx;
  481. SkScalar translateY = intPad - dy;
  482. // draw path to bitmap
  483. SkMatrix drawMatrix;
  484. drawMatrix.setScale(scale, scale);
  485. drawMatrix.postTranslate(translateX, translateY);
  486. SkASSERT(devPathBounds.fLeft == 0);
  487. SkASSERT(devPathBounds.fTop == 0);
  488. SkASSERT(devPathBounds.width() > 0);
  489. SkASSERT(devPathBounds.height() > 0);
  490. // setup signed distance field storage
  491. SkIRect dfBounds = devPathBounds.makeOutset(SK_DistanceFieldPad, SK_DistanceFieldPad);
  492. width = dfBounds.width();
  493. height = dfBounds.height();
  494. // TODO We should really generate this directly into the plot somehow
  495. SkAutoSMalloc<1024> dfStorage(width * height * sizeof(unsigned char));
  496. SkPath path;
  497. shape.asPath(&path);
  498. #ifndef SK_USE_LEGACY_DISTANCE_FIELDS
  499. // Generate signed distance field directly from SkPath
  500. bool succeed = GrGenerateDistanceFieldFromPath((unsigned char*)dfStorage.get(),
  501. path, drawMatrix,
  502. width, height, width * sizeof(unsigned char));
  503. if (!succeed) {
  504. #endif
  505. // setup bitmap backing
  506. SkAutoPixmapStorage dst;
  507. if (!dst.tryAlloc(SkImageInfo::MakeA8(devPathBounds.width(),
  508. devPathBounds.height()))) {
  509. return false;
  510. }
  511. sk_bzero(dst.writable_addr(), dst.computeByteSize());
  512. // rasterize path
  513. SkPaint paint;
  514. paint.setStyle(SkPaint::kFill_Style);
  515. paint.setAntiAlias(true);
  516. SkDraw draw;
  517. SkRasterClip rasterClip;
  518. rasterClip.setRect(devPathBounds);
  519. draw.fRC = &rasterClip;
  520. draw.fMatrix = &drawMatrix;
  521. draw.fDst = dst;
  522. draw.drawPathCoverage(path, paint);
  523. // Generate signed distance field
  524. SkGenerateDistanceFieldFromA8Image((unsigned char*)dfStorage.get(),
  525. (const unsigned char*)dst.addr(),
  526. dst.width(), dst.height(), dst.rowBytes());
  527. #ifndef SK_USE_LEGACY_DISTANCE_FIELDS
  528. }
  529. #endif
  530. // add to atlas
  531. SkIPoint16 atlasLocation;
  532. GrDrawOpAtlas::AtlasID id;
  533. if (!this->addToAtlas(target, flushInfo, atlas,
  534. width, height, dfStorage.get(), &id, &atlasLocation)) {
  535. return false;
  536. }
  537. // add to cache
  538. shapeData->fKey.set(shape, dimension);
  539. shapeData->fID = id;
  540. shapeData->fBounds = SkRect::Make(devPathBounds);
  541. shapeData->fBounds.offset(-translateX, -translateY);
  542. shapeData->fBounds.fLeft /= scale;
  543. shapeData->fBounds.fTop /= scale;
  544. shapeData->fBounds.fRight /= scale;
  545. shapeData->fBounds.fBottom /= scale;
  546. // We pack the 2bit page index in the low bit of the u and v texture coords
  547. uint16_t pageIndex = GrDrawOpAtlas::GetPageIndexFromID(id);
  548. SkASSERT(pageIndex < 4);
  549. uint16_t uBit = (pageIndex >> 1) & 0x1;
  550. uint16_t vBit = pageIndex & 0x1;
  551. shapeData->fTextureCoords.set((atlasLocation.fX+SK_DistanceFieldPad) << 1 | uBit,
  552. (atlasLocation.fY+SK_DistanceFieldPad) << 1 | vBit,
  553. (atlasLocation.fX+SK_DistanceFieldPad+
  554. devPathBounds.width()) << 1 | uBit,
  555. (atlasLocation.fY+SK_DistanceFieldPad+
  556. devPathBounds.height()) << 1 | vBit);
  557. fShapeCache->add(shapeData);
  558. fShapeList->addToTail(shapeData);
  559. #ifdef DF_PATH_TRACKING
  560. ++g_NumCachedPaths;
  561. #endif
  562. return true;
  563. }
  564. bool addBMPathToAtlas(GrMeshDrawOp::Target* target, FlushInfo* flushInfo,
  565. GrDrawOpAtlas* atlas, ShapeData* shapeData, const GrShape& shape,
  566. const SkMatrix& ctm) const {
  567. const SkRect& bounds = shape.bounds();
  568. if (bounds.isEmpty()) {
  569. return false;
  570. }
  571. SkMatrix drawMatrix(ctm);
  572. SkScalar tx = ctm.getTranslateX();
  573. SkScalar ty = ctm.getTranslateY();
  574. tx -= SkScalarFloorToScalar(tx);
  575. ty -= SkScalarFloorToScalar(ty);
  576. drawMatrix.set(SkMatrix::kMTransX, tx);
  577. drawMatrix.set(SkMatrix::kMTransY, ty);
  578. SkRect shapeDevBounds;
  579. drawMatrix.mapRect(&shapeDevBounds, bounds);
  580. SkScalar dx = SkScalarFloorToScalar(shapeDevBounds.fLeft);
  581. SkScalar dy = SkScalarFloorToScalar(shapeDevBounds.fTop);
  582. // get integer boundary
  583. SkIRect devPathBounds;
  584. shapeDevBounds.roundOut(&devPathBounds);
  585. // pad to allow room for antialiasing
  586. const int intPad = SkScalarCeilToInt(kAntiAliasPad);
  587. // place devBounds at origin
  588. int width = devPathBounds.width() + 2 * intPad;
  589. int height = devPathBounds.height() + 2 * intPad;
  590. devPathBounds = SkIRect::MakeWH(width, height);
  591. SkScalar translateX = intPad - dx;
  592. SkScalar translateY = intPad - dy;
  593. SkASSERT(devPathBounds.fLeft == 0);
  594. SkASSERT(devPathBounds.fTop == 0);
  595. SkASSERT(devPathBounds.width() > 0);
  596. SkASSERT(devPathBounds.height() > 0);
  597. SkPath path;
  598. shape.asPath(&path);
  599. // setup bitmap backing
  600. SkAutoPixmapStorage dst;
  601. if (!dst.tryAlloc(SkImageInfo::MakeA8(devPathBounds.width(),
  602. devPathBounds.height()))) {
  603. return false;
  604. }
  605. sk_bzero(dst.writable_addr(), dst.computeByteSize());
  606. // rasterize path
  607. SkPaint paint;
  608. paint.setStyle(SkPaint::kFill_Style);
  609. paint.setAntiAlias(true);
  610. SkDraw draw;
  611. SkRasterClip rasterClip;
  612. rasterClip.setRect(devPathBounds);
  613. draw.fRC = &rasterClip;
  614. drawMatrix.postTranslate(translateX, translateY);
  615. draw.fMatrix = &drawMatrix;
  616. draw.fDst = dst;
  617. draw.drawPathCoverage(path, paint);
  618. // add to atlas
  619. SkIPoint16 atlasLocation;
  620. GrDrawOpAtlas::AtlasID id;
  621. if (!this->addToAtlas(target, flushInfo, atlas,
  622. dst.width(), dst.height(), dst.addr(), &id, &atlasLocation)) {
  623. return false;
  624. }
  625. // add to cache
  626. shapeData->fKey.set(shape, ctm);
  627. shapeData->fID = id;
  628. shapeData->fBounds = SkRect::Make(devPathBounds);
  629. shapeData->fBounds.offset(-translateX, -translateY);
  630. // We pack the 2bit page index in the low bit of the u and v texture coords
  631. uint16_t pageIndex = GrDrawOpAtlas::GetPageIndexFromID(id);
  632. SkASSERT(pageIndex < 4);
  633. uint16_t uBit = (pageIndex >> 1) & 0x1;
  634. uint16_t vBit = pageIndex & 0x1;
  635. shapeData->fTextureCoords.set(atlasLocation.fX << 1 | uBit, atlasLocation.fY << 1 | vBit,
  636. (atlasLocation.fX+width) << 1 | uBit,
  637. (atlasLocation.fY+height) << 1 | vBit);
  638. fShapeCache->add(shapeData);
  639. fShapeList->addToTail(shapeData);
  640. #ifdef DF_PATH_TRACKING
  641. ++g_NumCachedPaths;
  642. #endif
  643. return true;
  644. }
  645. void writePathVertices(GrDrawOpAtlas* atlas,
  646. GrVertexWriter& vertices,
  647. const GrVertexColor& color,
  648. const SkMatrix& ctm,
  649. const ShapeData* shapeData) const {
  650. SkRect translatedBounds(shapeData->fBounds);
  651. if (!fUsesDistanceField) {
  652. translatedBounds.offset(SkScalarFloorToScalar(ctm.get(SkMatrix::kMTransX)),
  653. SkScalarFloorToScalar(ctm.get(SkMatrix::kMTransY)));
  654. }
  655. // set up texture coordinates
  656. GrVertexWriter::TriStrip<uint16_t> texCoords{
  657. (uint16_t)shapeData->fTextureCoords.fLeft,
  658. (uint16_t)shapeData->fTextureCoords.fTop,
  659. (uint16_t)shapeData->fTextureCoords.fRight,
  660. (uint16_t)shapeData->fTextureCoords.fBottom
  661. };
  662. if (fUsesDistanceField && !ctm.hasPerspective()) {
  663. vertices.writeQuad(GrQuad::MakeFromRect(translatedBounds, ctm),
  664. color,
  665. texCoords);
  666. } else {
  667. vertices.writeQuad(GrVertexWriter::TriStripFromRect(translatedBounds),
  668. color,
  669. texCoords);
  670. }
  671. }
  672. void flush(GrMeshDrawOp::Target* target, FlushInfo* flushInfo) const {
  673. GrGeometryProcessor* gp = flushInfo->fGeometryProcessor.get();
  674. int numAtlasTextures = SkToInt(fAtlas->numActivePages());
  675. auto proxies = fAtlas->getProxies();
  676. if (gp->numTextureSamplers() != numAtlasTextures) {
  677. for (int i = gp->numTextureSamplers(); i < numAtlasTextures; ++i) {
  678. flushInfo->fFixedDynamicState->fPrimitiveProcessorTextures[i] = proxies[i].get();
  679. }
  680. // During preparation the number of atlas pages has increased.
  681. // Update the proxies used in the GP to match.
  682. if (fUsesDistanceField) {
  683. reinterpret_cast<GrDistanceFieldPathGeoProc*>(gp)->addNewProxies(
  684. fAtlas->getProxies(), fAtlas->numActivePages(), GrSamplerState::ClampBilerp());
  685. } else {
  686. reinterpret_cast<GrBitmapTextGeoProc*>(gp)->addNewProxies(
  687. fAtlas->getProxies(), fAtlas->numActivePages(), GrSamplerState::ClampNearest());
  688. }
  689. }
  690. if (flushInfo->fInstancesToFlush) {
  691. GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
  692. int maxInstancesPerDraw =
  693. static_cast<int>(flushInfo->fIndexBuffer->size() / sizeof(uint16_t) / 6);
  694. mesh->setIndexedPatterned(flushInfo->fIndexBuffer, kIndicesPerQuad, kVerticesPerQuad,
  695. flushInfo->fInstancesToFlush, maxInstancesPerDraw);
  696. mesh->setVertexData(flushInfo->fVertexBuffer, flushInfo->fVertexOffset);
  697. target->recordDraw(
  698. flushInfo->fGeometryProcessor, mesh, 1, flushInfo->fFixedDynamicState, nullptr);
  699. flushInfo->fVertexOffset += kVerticesPerQuad * flushInfo->fInstancesToFlush;
  700. flushInfo->fInstancesToFlush = 0;
  701. }
  702. }
  703. void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
  704. fHelper.executeDrawsAndUploads(this, flushState, chainBounds);
  705. }
  706. const SkPMColor4f& color() const { return fShapes[0].fColor; }
  707. bool usesDistanceField() const { return fUsesDistanceField; }
  708. CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
  709. SmallPathOp* that = t->cast<SmallPathOp>();
  710. if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
  711. return CombineResult::kCannotCombine;
  712. }
  713. if (this->usesDistanceField() != that->usesDistanceField()) {
  714. return CombineResult::kCannotCombine;
  715. }
  716. const SkMatrix& thisCtm = this->fShapes[0].fViewMatrix;
  717. const SkMatrix& thatCtm = that->fShapes[0].fViewMatrix;
  718. if (thisCtm.hasPerspective() != thatCtm.hasPerspective()) {
  719. return CombineResult::kCannotCombine;
  720. }
  721. // We can position on the cpu unless we're in perspective,
  722. // but also need to make sure local matrices are identical
  723. if ((thisCtm.hasPerspective() || fHelper.usesLocalCoords()) &&
  724. !thisCtm.cheapEqualTo(thatCtm)) {
  725. return CombineResult::kCannotCombine;
  726. }
  727. // Depending on the ctm we may have a different shader for SDF paths
  728. if (this->usesDistanceField()) {
  729. if (thisCtm.isScaleTranslate() != thatCtm.isScaleTranslate() ||
  730. thisCtm.isSimilarity() != thatCtm.isSimilarity()) {
  731. return CombineResult::kCannotCombine;
  732. }
  733. }
  734. fShapes.push_back_n(that->fShapes.count(), that->fShapes.begin());
  735. fWideColor |= that->fWideColor;
  736. return CombineResult::kMerged;
  737. }
  738. bool fUsesDistanceField;
  739. struct Entry {
  740. SkPMColor4f fColor;
  741. GrShape fShape;
  742. SkMatrix fViewMatrix;
  743. };
  744. SkSTArray<1, Entry> fShapes;
  745. Helper fHelper;
  746. GrDrawOpAtlas* fAtlas;
  747. ShapeCache* fShapeCache;
  748. ShapeDataList* fShapeList;
  749. bool fGammaCorrect;
  750. bool fWideColor;
  751. typedef GrMeshDrawOp INHERITED;
  752. };
  753. bool GrSmallPathRenderer::onDrawPath(const DrawPathArgs& args) {
  754. GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
  755. "GrSmallPathRenderer::onDrawPath");
  756. // we've already bailed on inverse filled paths, so this is safe
  757. SkASSERT(!args.fShape->isEmpty());
  758. SkASSERT(args.fShape->hasUnstyledKey());
  759. if (!fAtlas) {
  760. const GrBackendFormat format =
  761. args.fContext->priv().caps()->getBackendFormatFromColorType(
  762. GrColorType::kAlpha_8);
  763. fAtlas = GrDrawOpAtlas::Make(args.fContext->priv().proxyProvider(),
  764. format,
  765. GrColorType::kAlpha_8,
  766. ATLAS_TEXTURE_WIDTH, ATLAS_TEXTURE_HEIGHT,
  767. PLOT_WIDTH, PLOT_HEIGHT,
  768. GrDrawOpAtlas::AllowMultitexturing::kYes,
  769. &GrSmallPathRenderer::HandleEviction,
  770. (void*)this);
  771. if (!fAtlas) {
  772. return false;
  773. }
  774. }
  775. std::unique_ptr<GrDrawOp> op = SmallPathOp::Make(
  776. args.fContext, std::move(args.fPaint), *args.fShape, *args.fViewMatrix, fAtlas.get(),
  777. &fShapeCache, &fShapeList, args.fGammaCorrect, args.fUserStencilSettings);
  778. args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op));
  779. return true;
  780. }
  781. ///////////////////////////////////////////////////////////////////////////////////////////////////
  782. #if GR_TEST_UTILS
  783. struct GrSmallPathRenderer::PathTestStruct {
  784. PathTestStruct() : fContextID(SK_InvalidGenID), fAtlas(nullptr) {}
  785. ~PathTestStruct() { this->reset(); }
  786. void reset() {
  787. ShapeDataList::Iter iter;
  788. iter.init(fShapeList, ShapeDataList::Iter::kHead_IterStart);
  789. ShapeData* shapeData;
  790. while ((shapeData = iter.get())) {
  791. iter.next();
  792. fShapeList.remove(shapeData);
  793. delete shapeData;
  794. }
  795. fAtlas = nullptr;
  796. fShapeCache.reset();
  797. }
  798. static void HandleEviction(GrDrawOpAtlas::AtlasID id, void* pr) {
  799. PathTestStruct* dfpr = (PathTestStruct*)pr;
  800. // remove any paths that use this plot
  801. ShapeDataList::Iter iter;
  802. iter.init(dfpr->fShapeList, ShapeDataList::Iter::kHead_IterStart);
  803. ShapeData* shapeData;
  804. while ((shapeData = iter.get())) {
  805. iter.next();
  806. if (id == shapeData->fID) {
  807. dfpr->fShapeCache.remove(shapeData->fKey);
  808. dfpr->fShapeList.remove(shapeData);
  809. delete shapeData;
  810. }
  811. }
  812. }
  813. uint32_t fContextID;
  814. std::unique_ptr<GrDrawOpAtlas> fAtlas;
  815. ShapeCache fShapeCache;
  816. ShapeDataList fShapeList;
  817. };
  818. std::unique_ptr<GrDrawOp> GrSmallPathRenderer::createOp_TestingOnly(
  819. GrRecordingContext* context,
  820. GrPaint&& paint,
  821. const GrShape& shape,
  822. const SkMatrix& viewMatrix,
  823. GrDrawOpAtlas* atlas,
  824. ShapeCache* shapeCache,
  825. ShapeDataList* shapeList,
  826. bool gammaCorrect,
  827. const GrUserStencilSettings* stencil) {
  828. return GrSmallPathRenderer::SmallPathOp::Make(context, std::move(paint), shape, viewMatrix,
  829. atlas, shapeCache, shapeList, gammaCorrect,
  830. stencil);
  831. }
  832. GR_DRAW_OP_TEST_DEFINE(SmallPathOp) {
  833. using PathTestStruct = GrSmallPathRenderer::PathTestStruct;
  834. static PathTestStruct gTestStruct;
  835. if (context->priv().contextID() != gTestStruct.fContextID) {
  836. gTestStruct.fContextID = context->priv().contextID();
  837. gTestStruct.reset();
  838. const GrBackendFormat format =
  839. context->priv().caps()->getBackendFormatFromColorType(GrColorType::kAlpha_8);
  840. gTestStruct.fAtlas = GrDrawOpAtlas::Make(context->priv().proxyProvider(),
  841. format, GrColorType::kAlpha_8,
  842. ATLAS_TEXTURE_WIDTH, ATLAS_TEXTURE_HEIGHT,
  843. PLOT_WIDTH, PLOT_HEIGHT,
  844. GrDrawOpAtlas::AllowMultitexturing::kYes,
  845. &PathTestStruct::HandleEviction,
  846. (void*)&gTestStruct);
  847. }
  848. SkMatrix viewMatrix = GrTest::TestMatrix(random);
  849. bool gammaCorrect = random->nextBool();
  850. // This path renderer only allows fill styles.
  851. GrShape shape(GrTest::TestPath(random), GrStyle::SimpleFill());
  852. return GrSmallPathRenderer::createOp_TestingOnly(
  853. context,
  854. std::move(paint), shape, viewMatrix,
  855. gTestStruct.fAtlas.get(),
  856. &gTestStruct.fShapeCache,
  857. &gTestStruct.fShapeList,
  858. gammaCorrect,
  859. GrGetRandomStencil(random, context));
  860. }
  861. #endif