GrTextBlobVertexRegenerator.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. /*
  2. * Copyright 2016 Google Inc.
  3. *
  4. * Use of this source code is governed by a BSD-style license that can be
  5. * found in the LICENSE file.
  6. */
  7. #include "src/core/SkDistanceFieldGen.h"
  8. #include "src/gpu/ops/GrAtlasTextOp.h"
  9. #include "src/gpu/text/GrAtlasManager.h"
  10. #include "src/gpu/text/GrTextBlob.h"
  11. #include "src/gpu/text/GrTextTarget.h"
  12. enum RegenMask {
  13. kNoRegen = 0x0,
  14. kRegenPos = 0x1,
  15. kRegenCol = 0x2,
  16. kRegenTex = 0x4,
  17. kRegenGlyph = 0x8,
  18. };
  19. ////////////////////////////////////////////////////////////////////////////////////////////////////
  20. static void regen_positions(char* vertex, size_t vertexStride, SkScalar transX, SkScalar transY) {
  21. SkPoint* point = reinterpret_cast<SkPoint*>(vertex);
  22. for (int i = 0; i < 4; ++i) {
  23. point->fX += transX;
  24. point->fY += transY;
  25. point = SkTAddOffset<SkPoint>(point, vertexStride);
  26. }
  27. }
  28. static void regen_colors(char* vertex, size_t vertexStride, GrColor color) {
  29. // This is a bit wonky, but sometimes we have LCD text, in which case we won't have color
  30. // vertices, hence vertexStride - sizeof(SkIPoint16)
  31. size_t colorOffset = vertexStride - sizeof(SkIPoint16) - sizeof(GrColor);
  32. GrColor* vcolor = reinterpret_cast<GrColor*>(vertex + colorOffset);
  33. for (int i = 0; i < 4; ++i) {
  34. *vcolor = color;
  35. vcolor = SkTAddOffset<GrColor>(vcolor, vertexStride);
  36. }
  37. }
  38. static void regen_texcoords(char* vertex, size_t vertexStride, const GrGlyph* glyph,
  39. bool useDistanceFields) {
  40. // This is a bit wonky, but sometimes we have LCD text, in which case we won't have color
  41. // vertices, hence vertexStride - sizeof(SkIPoint16)
  42. size_t texCoordOffset = vertexStride - sizeof(SkIPoint16);
  43. uint16_t u0, v0, u1, v1;
  44. SkASSERT(glyph);
  45. int width = glyph->fBounds.width();
  46. int height = glyph->fBounds.height();
  47. if (useDistanceFields) {
  48. u0 = glyph->fAtlasLocation.fX + SK_DistanceFieldInset;
  49. v0 = glyph->fAtlasLocation.fY + SK_DistanceFieldInset;
  50. u1 = u0 + width - 2 * SK_DistanceFieldInset;
  51. v1 = v0 + height - 2 * SK_DistanceFieldInset;
  52. } else {
  53. u0 = glyph->fAtlasLocation.fX;
  54. v0 = glyph->fAtlasLocation.fY;
  55. u1 = u0 + width;
  56. v1 = v0 + height;
  57. }
  58. // We pack the 2bit page index in the low bit of the u and v texture coords
  59. uint32_t pageIndex = glyph->pageIndex();
  60. SkASSERT(pageIndex < 4);
  61. uint16_t uBit = (pageIndex >> 1) & 0x1;
  62. uint16_t vBit = pageIndex & 0x1;
  63. u0 <<= 1;
  64. u0 |= uBit;
  65. v0 <<= 1;
  66. v0 |= vBit;
  67. u1 <<= 1;
  68. u1 |= uBit;
  69. v1 <<= 1;
  70. v1 |= vBit;
  71. uint16_t* textureCoords = reinterpret_cast<uint16_t*>(vertex + texCoordOffset);
  72. textureCoords[0] = u0;
  73. textureCoords[1] = v0;
  74. textureCoords = SkTAddOffset<uint16_t>(textureCoords, vertexStride);
  75. textureCoords[0] = u0;
  76. textureCoords[1] = v1;
  77. textureCoords = SkTAddOffset<uint16_t>(textureCoords, vertexStride);
  78. textureCoords[0] = u1;
  79. textureCoords[1] = v0;
  80. textureCoords = SkTAddOffset<uint16_t>(textureCoords, vertexStride);
  81. textureCoords[0] = u1;
  82. textureCoords[1] = v1;
  83. #ifdef DISPLAY_PAGE_INDEX
  84. // Enable this to visualize the page from which each glyph is being drawn.
  85. // Green Red Magenta Cyan -> 0 1 2 3; Black -> error
  86. GrColor hackColor;
  87. switch (pageIndex) {
  88. case 0:
  89. hackColor = GrColorPackRGBA(0, 255, 0, 255);
  90. break;
  91. case 1:
  92. hackColor = GrColorPackRGBA(255, 0, 0, 255);;
  93. break;
  94. case 2:
  95. hackColor = GrColorPackRGBA(255, 0, 255, 255);
  96. break;
  97. case 3:
  98. hackColor = GrColorPackRGBA(0, 255, 255, 255);
  99. break;
  100. default:
  101. hackColor = GrColorPackRGBA(0, 0, 0, 255);
  102. break;
  103. }
  104. regen_colors(vertex, vertexStride, hackColor);
  105. #endif
  106. }
  107. GrTextBlob::VertexRegenerator::VertexRegenerator(GrResourceProvider* resourceProvider,
  108. GrTextBlob* blob,
  109. int runIdx, int subRunIdx,
  110. const SkMatrix& viewMatrix, SkScalar x, SkScalar y,
  111. GrColor color,
  112. GrDeferredUploadTarget* uploadTarget,
  113. GrStrikeCache* glyphCache,
  114. GrAtlasManager* fullAtlasManager,
  115. SkExclusiveStrikePtr* lazyStrike)
  116. : fResourceProvider(resourceProvider)
  117. , fViewMatrix(viewMatrix)
  118. , fBlob(blob)
  119. , fUploadTarget(uploadTarget)
  120. , fGlyphCache(glyphCache)
  121. , fFullAtlasManager(fullAtlasManager)
  122. , fLazyStrike(lazyStrike)
  123. , fSubRun(&blob->fRuns[runIdx].fSubRunInfo[subRunIdx])
  124. , fColor(color) {
  125. // Compute translation if any
  126. fSubRun->computeTranslation(fViewMatrix, x, y, &fTransX, &fTransY);
  127. // Because the GrStrikeCache may evict the strike a blob depends on using for
  128. // generating its texture coords, we have to track whether or not the strike has
  129. // been abandoned. If it hasn't been abandoned, then we can use the GrGlyph*s as is
  130. // otherwise we have to get the new strike, and use that to get the correct glyphs.
  131. // Because we do not have the packed ids, and thus can't look up our glyphs in the
  132. // new strike, we instead keep our ref to the old strike and use the packed ids from
  133. // it. These ids will still be valid as long as we hold the ref. When we are done
  134. // updating our cache of the GrGlyph*s, we drop our ref on the old strike
  135. if (fSubRun->strike()->isAbandoned()) {
  136. fRegenFlags |= kRegenGlyph;
  137. fRegenFlags |= kRegenTex;
  138. }
  139. if (kARGB_GrMaskFormat != fSubRun->maskFormat() && fSubRun->color() != color) {
  140. fRegenFlags |= kRegenCol;
  141. }
  142. if (0.f != fTransX || 0.f != fTransY) {
  143. fRegenFlags |= kRegenPos;
  144. }
  145. }
  146. bool GrTextBlob::VertexRegenerator::doRegen(GrTextBlob::VertexRegenerator::Result* result,
  147. bool regenPos, bool regenCol, bool regenTexCoords,
  148. bool regenGlyphs) {
  149. SkASSERT(!regenGlyphs || regenTexCoords);
  150. sk_sp<GrTextStrike> strike;
  151. if (regenTexCoords) {
  152. fSubRun->resetBulkUseToken();
  153. const SkStrikeSpec& strikeSpec = fSubRun->strikeSpec();
  154. if (!*fLazyStrike || (*fLazyStrike)->getDescriptor() != strikeSpec.descriptor()) {
  155. *fLazyStrike =
  156. strikeSpec.findOrCreateExclusiveStrike(SkStrikeCache::GlobalStrikeCache());
  157. }
  158. if (regenGlyphs) {
  159. strike = strikeSpec.findOrCreateGrStrike(fGlyphCache);
  160. } else {
  161. strike = fSubRun->refStrike();
  162. }
  163. }
  164. bool hasW = fSubRun->hasWCoord();
  165. auto vertexStride = GetVertexStride(fSubRun->maskFormat(), hasW);
  166. char* currVertex = fBlob->fVertices + fSubRun->vertexStartIndex() +
  167. fCurrGlyph * kVerticesPerGlyph * vertexStride;
  168. result->fFirstVertex = currVertex;
  169. for (int glyphIdx = fCurrGlyph; glyphIdx < (int)fSubRun->glyphCount(); glyphIdx++) {
  170. GrGlyph* glyph = nullptr;
  171. if (regenTexCoords) {
  172. size_t glyphOffset = glyphIdx + fSubRun->glyphStartIndex();
  173. if (regenGlyphs) {
  174. // Get the id from the old glyph, and use the new strike to lookup
  175. // the glyph.
  176. SkPackedGlyphID id = fBlob->fGlyphs[glyphOffset]->fPackedID;
  177. fBlob->fGlyphs[glyphOffset] = strike->getGlyph(id, fLazyStrike->get());
  178. SkASSERT(id == fBlob->fGlyphs[glyphOffset]->fPackedID);
  179. }
  180. glyph = fBlob->fGlyphs[glyphOffset];
  181. SkASSERT(glyph && glyph->fMaskFormat == fSubRun->maskFormat());
  182. if (!fFullAtlasManager->hasGlyph(glyph)) {
  183. GrDrawOpAtlas::ErrorCode code;
  184. code = strike->addGlyphToAtlas(fResourceProvider, fUploadTarget, fGlyphCache,
  185. fFullAtlasManager, glyph,
  186. fLazyStrike->get(), fSubRun->maskFormat(),
  187. fSubRun->needsTransform());
  188. if (GrDrawOpAtlas::ErrorCode::kError == code) {
  189. // Something horrible has happened - drop the op
  190. return false;
  191. }
  192. else if (GrDrawOpAtlas::ErrorCode::kTryAgain == code) {
  193. fBrokenRun = glyphIdx > 0;
  194. result->fFinished = false;
  195. return true;
  196. }
  197. }
  198. auto tokenTracker = fUploadTarget->tokenTracker();
  199. fFullAtlasManager->addGlyphToBulkAndSetUseToken(fSubRun->bulkUseToken(), glyph,
  200. tokenTracker->nextDrawToken());
  201. }
  202. if (regenPos) {
  203. regen_positions(currVertex, vertexStride, fTransX, fTransY);
  204. }
  205. if (regenCol) {
  206. regen_colors(currVertex, vertexStride, fColor);
  207. }
  208. if (regenTexCoords) {
  209. regen_texcoords(currVertex, vertexStride, glyph, fSubRun->drawAsDistanceFields());
  210. }
  211. currVertex += vertexStride * GrAtlasTextOp::kVerticesPerGlyph;
  212. ++result->fGlyphsRegenerated;
  213. ++fCurrGlyph;
  214. }
  215. // We may have changed the color so update it here
  216. fSubRun->setColor(fColor);
  217. if (regenTexCoords) {
  218. if (regenGlyphs) {
  219. fSubRun->setStrike(std::move(strike));
  220. }
  221. fSubRun->setAtlasGeneration(fBrokenRun
  222. ? GrDrawOpAtlas::kInvalidAtlasGeneration
  223. : fFullAtlasManager->atlasGeneration(fSubRun->maskFormat()));
  224. } else {
  225. // For the non-texCoords case we need to ensure that we update the associated use tokens
  226. fFullAtlasManager->setUseTokenBulk(*fSubRun->bulkUseToken(),
  227. fUploadTarget->tokenTracker()->nextDrawToken(),
  228. fSubRun->maskFormat());
  229. }
  230. return true;
  231. }
  232. bool GrTextBlob::VertexRegenerator::regenerate(GrTextBlob::VertexRegenerator::Result* result) {
  233. uint64_t currentAtlasGen = fFullAtlasManager->atlasGeneration(fSubRun->maskFormat());
  234. // If regenerate() is called multiple times then the atlas gen may have changed. So we check
  235. // this each time.
  236. if (fSubRun->atlasGeneration() != currentAtlasGen) {
  237. fRegenFlags |= kRegenTex;
  238. }
  239. if (fRegenFlags) {
  240. return this->doRegen(result,
  241. fRegenFlags & kRegenPos,
  242. fRegenFlags & kRegenCol,
  243. fRegenFlags & kRegenTex,
  244. fRegenFlags & kRegenGlyph);
  245. } else {
  246. bool hasW = fSubRun->hasWCoord();
  247. auto vertexStride = GetVertexStride(fSubRun->maskFormat(), hasW);
  248. result->fFinished = true;
  249. result->fGlyphsRegenerated = fSubRun->glyphCount() - fCurrGlyph;
  250. result->fFirstVertex = fBlob->fVertices + fSubRun->vertexStartIndex() +
  251. fCurrGlyph * kVerticesPerGlyph * vertexStride;
  252. fCurrGlyph = fSubRun->glyphCount();
  253. // set use tokens for all of the glyphs in our subrun. This is only valid if we
  254. // have a valid atlas generation
  255. fFullAtlasManager->setUseTokenBulk(*fSubRun->bulkUseToken(),
  256. fUploadTarget->tokenTracker()->nextDrawToken(),
  257. fSubRun->maskFormat());
  258. return true;
  259. }
  260. SK_ABORT("Should not get here");
  261. return false;
  262. }