GrAtlasTextOp.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  1. /*
  2. * Copyright 2015 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/gpu/ops/GrAtlasTextOp.h"
  8. #include "include/core/SkPoint3.h"
  9. #include "include/private/GrRecordingContext.h"
  10. #include "src/core/SkMathPriv.h"
  11. #include "src/core/SkMatrixPriv.h"
  12. #include "src/core/SkStrikeCache.h"
  13. #include "src/gpu/GrCaps.h"
  14. #include "src/gpu/GrMemoryPool.h"
  15. #include "src/gpu/GrOpFlushState.h"
  16. #include "src/gpu/GrRecordingContextPriv.h"
  17. #include "src/gpu/GrResourceProvider.h"
  18. #include "src/gpu/effects/GrBitmapTextGeoProc.h"
  19. #include "src/gpu/effects/GrDistanceFieldGeoProc.h"
  20. #include "src/gpu/text/GrAtlasManager.h"
  21. #include "src/gpu/text/GrStrikeCache.h"
  22. ///////////////////////////////////////////////////////////////////////////////////////////////////
  23. std::unique_ptr<GrAtlasTextOp> GrAtlasTextOp::MakeBitmap(GrRecordingContext* context,
  24. GrPaint&& paint,
  25. GrMaskFormat maskFormat,
  26. int glyphCount,
  27. bool needsTransform) {
  28. GrOpMemoryPool* pool = context->priv().opMemoryPool();
  29. std::unique_ptr<GrAtlasTextOp> op = pool->allocate<GrAtlasTextOp>(std::move(paint));
  30. switch (maskFormat) {
  31. case kA8_GrMaskFormat:
  32. op->fMaskType = kGrayscaleCoverageMask_MaskType;
  33. break;
  34. case kA565_GrMaskFormat:
  35. op->fMaskType = kLCDCoverageMask_MaskType;
  36. break;
  37. case kARGB_GrMaskFormat:
  38. op->fMaskType = kColorBitmapMask_MaskType;
  39. break;
  40. }
  41. op->fNumGlyphs = glyphCount;
  42. op->fGeoCount = 1;
  43. op->fLuminanceColor = 0;
  44. op->fNeedsGlyphTransform = needsTransform;
  45. return op;
  46. }
  47. std::unique_ptr<GrAtlasTextOp> GrAtlasTextOp::MakeDistanceField(
  48. GrRecordingContext* context,
  49. GrPaint&& paint,
  50. int glyphCount,
  51. const GrDistanceFieldAdjustTable* distanceAdjustTable,
  52. bool useGammaCorrectDistanceTable,
  53. SkColor luminanceColor,
  54. const SkSurfaceProps& props,
  55. bool isAntiAliased,
  56. bool useLCD) {
  57. GrOpMemoryPool* pool = context->priv().opMemoryPool();
  58. std::unique_ptr<GrAtlasTextOp> op = pool->allocate<GrAtlasTextOp>(std::move(paint));
  59. bool isBGR = SkPixelGeometryIsBGR(props.pixelGeometry());
  60. bool isLCD = useLCD && SkPixelGeometryIsH(props.pixelGeometry());
  61. op->fMaskType = !isAntiAliased ? kAliasedDistanceField_MaskType
  62. : isLCD ? (isBGR ? kLCDBGRDistanceField_MaskType
  63. : kLCDDistanceField_MaskType)
  64. : kGrayscaleDistanceField_MaskType;
  65. op->fDistanceAdjustTable.reset(SkRef(distanceAdjustTable));
  66. op->fUseGammaCorrectDistanceTable = useGammaCorrectDistanceTable;
  67. op->fLuminanceColor = luminanceColor;
  68. op->fNumGlyphs = glyphCount;
  69. op->fGeoCount = 1;
  70. return op;
  71. }
  72. static const int kDistanceAdjustLumShift = 5;
  73. void GrAtlasTextOp::init() {
  74. const Geometry& geo = fGeoData[0];
  75. if (this->usesDistanceFields()) {
  76. bool isLCD = this->isLCD();
  77. const SkMatrix& viewMatrix = geo.fViewMatrix;
  78. fDFGPFlags = viewMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
  79. fDFGPFlags |= viewMatrix.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0;
  80. fDFGPFlags |= viewMatrix.hasPerspective() ? kPerspective_DistanceFieldEffectFlag : 0;
  81. fDFGPFlags |= fUseGammaCorrectDistanceTable ? kGammaCorrect_DistanceFieldEffectFlag : 0;
  82. fDFGPFlags |= (kAliasedDistanceField_MaskType == fMaskType)
  83. ? kAliased_DistanceFieldEffectFlag
  84. : 0;
  85. if (isLCD) {
  86. fDFGPFlags |= kUseLCD_DistanceFieldEffectFlag;
  87. fDFGPFlags |=
  88. (kLCDBGRDistanceField_MaskType == fMaskType) ? kBGR_DistanceFieldEffectFlag : 0;
  89. }
  90. fNeedsGlyphTransform = true;
  91. }
  92. SkRect bounds;
  93. geo.fBlob->computeSubRunBounds(&bounds, geo.fRun, geo.fSubRun, geo.fViewMatrix, geo.fX, geo.fY,
  94. fNeedsGlyphTransform);
  95. // We don't have tight bounds on the glyph paths in device space. For the purposes of bounds
  96. // we treat this as a set of non-AA rects rendered with a texture.
  97. this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo);
  98. }
  99. void GrAtlasTextOp::visitProxies(const VisitProxyFunc& func) const {
  100. fProcessors.visitProxies(func);
  101. }
  102. #ifdef SK_DEBUG
  103. SkString GrAtlasTextOp::dumpInfo() const {
  104. SkString str;
  105. for (int i = 0; i < fGeoCount; ++i) {
  106. str.appendf("%d: Color: 0x%08x Trans: %.2f,%.2f Runs: %d\n",
  107. i,
  108. fGeoData[i].fColor.toBytes_RGBA(),
  109. fGeoData[i].fX,
  110. fGeoData[i].fY,
  111. fGeoData[i].fBlob->runCountLimit());
  112. }
  113. str += fProcessors.dumpProcessors();
  114. str += INHERITED::dumpInfo();
  115. return str;
  116. }
  117. #endif
  118. GrDrawOp::FixedFunctionFlags GrAtlasTextOp::fixedFunctionFlags() const {
  119. return FixedFunctionFlags::kNone;
  120. }
  121. GrProcessorSet::Analysis GrAtlasTextOp::finalize(
  122. const GrCaps& caps, const GrAppliedClip* clip, bool hasMixedSampledCoverage,
  123. GrClampType clampType) {
  124. GrProcessorAnalysisCoverage coverage;
  125. GrProcessorAnalysisColor color;
  126. if (kColorBitmapMask_MaskType == fMaskType) {
  127. color.setToUnknown();
  128. } else {
  129. color.setToConstant(this->color());
  130. }
  131. switch (fMaskType) {
  132. case kGrayscaleCoverageMask_MaskType:
  133. case kAliasedDistanceField_MaskType:
  134. case kGrayscaleDistanceField_MaskType:
  135. coverage = GrProcessorAnalysisCoverage::kSingleChannel;
  136. break;
  137. case kLCDCoverageMask_MaskType:
  138. case kLCDDistanceField_MaskType:
  139. case kLCDBGRDistanceField_MaskType:
  140. coverage = GrProcessorAnalysisCoverage::kLCD;
  141. break;
  142. case kColorBitmapMask_MaskType:
  143. coverage = GrProcessorAnalysisCoverage::kNone;
  144. break;
  145. }
  146. auto analysis = fProcessors.finalize(
  147. color, coverage, clip, &GrUserStencilSettings::kUnused, hasMixedSampledCoverage, caps,
  148. clampType, &fGeoData[0].fColor);
  149. fUsesLocalCoords = analysis.usesLocalCoords();
  150. return analysis;
  151. }
  152. static void clip_quads(const SkIRect& clipRect, char* currVertex, const char* blobVertices,
  153. size_t vertexStride, int glyphCount) {
  154. for (int i = 0; i < glyphCount; ++i) {
  155. const SkPoint* blobPositionLT = reinterpret_cast<const SkPoint*>(blobVertices);
  156. const SkPoint* blobPositionRB =
  157. reinterpret_cast<const SkPoint*>(blobVertices + 3 * vertexStride);
  158. // positions for bitmap glyphs are pixel boundary aligned
  159. SkIRect positionRect = SkIRect::MakeLTRB(SkScalarRoundToInt(blobPositionLT->fX),
  160. SkScalarRoundToInt(blobPositionLT->fY),
  161. SkScalarRoundToInt(blobPositionRB->fX),
  162. SkScalarRoundToInt(blobPositionRB->fY));
  163. if (clipRect.contains(positionRect)) {
  164. memcpy(currVertex, blobVertices, 4 * vertexStride);
  165. currVertex += 4 * vertexStride;
  166. } else {
  167. // Pull out some more data that we'll need.
  168. // In the LCD case the color will be garbage, but we'll overwrite it with the texcoords
  169. // and it avoids a lot of conditionals.
  170. auto color = *reinterpret_cast<const SkColor*>(blobVertices + sizeof(SkPoint));
  171. size_t coordOffset = vertexStride - 2*sizeof(uint16_t);
  172. auto* blobCoordsLT = reinterpret_cast<const uint16_t*>(blobVertices + coordOffset);
  173. auto* blobCoordsRB = reinterpret_cast<const uint16_t*>(blobVertices + 3 * vertexStride +
  174. coordOffset);
  175. // Pull out the texel coordinates and texture index bits
  176. uint16_t coordsRectL = blobCoordsLT[0] >> 1;
  177. uint16_t coordsRectT = blobCoordsLT[1] >> 1;
  178. uint16_t coordsRectR = blobCoordsRB[0] >> 1;
  179. uint16_t coordsRectB = blobCoordsRB[1] >> 1;
  180. uint16_t pageIndexX = blobCoordsLT[0] & 0x1;
  181. uint16_t pageIndexY = blobCoordsLT[1] & 0x1;
  182. int positionRectWidth = positionRect.width();
  183. int positionRectHeight = positionRect.height();
  184. SkASSERT(positionRectWidth == (coordsRectR - coordsRectL));
  185. SkASSERT(positionRectHeight == (coordsRectB - coordsRectT));
  186. // Clip position and texCoords to the clipRect
  187. unsigned int delta;
  188. delta = SkTMin(SkTMax(clipRect.fLeft - positionRect.fLeft, 0), positionRectWidth);
  189. coordsRectL += delta;
  190. positionRect.fLeft += delta;
  191. delta = SkTMin(SkTMax(clipRect.fTop - positionRect.fTop, 0), positionRectHeight);
  192. coordsRectT += delta;
  193. positionRect.fTop += delta;
  194. delta = SkTMin(SkTMax(positionRect.fRight - clipRect.fRight, 0), positionRectWidth);
  195. coordsRectR -= delta;
  196. positionRect.fRight -= delta;
  197. delta = SkTMin(SkTMax(positionRect.fBottom - clipRect.fBottom, 0), positionRectHeight);
  198. coordsRectB -= delta;
  199. positionRect.fBottom -= delta;
  200. // Repack texel coordinates and index
  201. coordsRectL = coordsRectL << 1 | pageIndexX;
  202. coordsRectT = coordsRectT << 1 | pageIndexY;
  203. coordsRectR = coordsRectR << 1 | pageIndexX;
  204. coordsRectB = coordsRectB << 1 | pageIndexY;
  205. // Set new positions and coords
  206. SkPoint* currPosition = reinterpret_cast<SkPoint*>(currVertex);
  207. currPosition->fX = positionRect.fLeft;
  208. currPosition->fY = positionRect.fTop;
  209. *(reinterpret_cast<SkColor*>(currVertex + sizeof(SkPoint))) = color;
  210. uint16_t* currCoords = reinterpret_cast<uint16_t*>(currVertex + coordOffset);
  211. currCoords[0] = coordsRectL;
  212. currCoords[1] = coordsRectT;
  213. currVertex += vertexStride;
  214. currPosition = reinterpret_cast<SkPoint*>(currVertex);
  215. currPosition->fX = positionRect.fLeft;
  216. currPosition->fY = positionRect.fBottom;
  217. *(reinterpret_cast<SkColor*>(currVertex + sizeof(SkPoint))) = color;
  218. currCoords = reinterpret_cast<uint16_t*>(currVertex + coordOffset);
  219. currCoords[0] = coordsRectL;
  220. currCoords[1] = coordsRectB;
  221. currVertex += vertexStride;
  222. currPosition = reinterpret_cast<SkPoint*>(currVertex);
  223. currPosition->fX = positionRect.fRight;
  224. currPosition->fY = positionRect.fTop;
  225. *(reinterpret_cast<SkColor*>(currVertex + sizeof(SkPoint))) = color;
  226. currCoords = reinterpret_cast<uint16_t*>(currVertex + coordOffset);
  227. currCoords[0] = coordsRectR;
  228. currCoords[1] = coordsRectT;
  229. currVertex += vertexStride;
  230. currPosition = reinterpret_cast<SkPoint*>(currVertex);
  231. currPosition->fX = positionRect.fRight;
  232. currPosition->fY = positionRect.fBottom;
  233. *(reinterpret_cast<SkColor*>(currVertex + sizeof(SkPoint))) = color;
  234. currCoords = reinterpret_cast<uint16_t*>(currVertex + coordOffset);
  235. currCoords[0] = coordsRectR;
  236. currCoords[1] = coordsRectB;
  237. currVertex += vertexStride;
  238. }
  239. blobVertices += 4 * vertexStride;
  240. }
  241. }
  242. void GrAtlasTextOp::onPrepareDraws(Target* target) {
  243. auto resourceProvider = target->resourceProvider();
  244. // if we have RGB, then we won't have any SkShaders so no need to use a localmatrix.
  245. // TODO actually only invert if we don't have RGBA
  246. SkMatrix localMatrix;
  247. if (this->usesLocalCoords() && !fGeoData[0].fViewMatrix.invert(&localMatrix)) {
  248. return;
  249. }
  250. GrAtlasManager* atlasManager = target->atlasManager();
  251. GrStrikeCache* glyphCache = target->glyphCache();
  252. GrMaskFormat maskFormat = this->maskFormat();
  253. unsigned int numActiveProxies;
  254. const sk_sp<GrTextureProxy>* proxies = atlasManager->getProxies(maskFormat, &numActiveProxies);
  255. if (!proxies) {
  256. SkDebugf("Could not allocate backing texture for atlas\n");
  257. return;
  258. }
  259. SkASSERT(proxies[0]);
  260. static constexpr int kMaxTextures = GrBitmapTextGeoProc::kMaxTextures;
  261. GR_STATIC_ASSERT(GrDistanceFieldA8TextGeoProc::kMaxTextures == kMaxTextures);
  262. GR_STATIC_ASSERT(GrDistanceFieldLCDTextGeoProc::kMaxTextures == kMaxTextures);
  263. auto fixedDynamicState = target->makeFixedDynamicState(kMaxTextures);
  264. for (unsigned i = 0; i < numActiveProxies; ++i) {
  265. fixedDynamicState->fPrimitiveProcessorTextures[i] = proxies[i].get();
  266. }
  267. FlushInfo flushInfo;
  268. flushInfo.fFixedDynamicState = fixedDynamicState;
  269. bool vmPerspective = fGeoData[0].fViewMatrix.hasPerspective();
  270. if (this->usesDistanceFields()) {
  271. flushInfo.fGeometryProcessor = this->setupDfProcessor(*target->caps().shaderCaps(),
  272. proxies, numActiveProxies);
  273. } else {
  274. GrSamplerState samplerState = fNeedsGlyphTransform ? GrSamplerState::ClampBilerp()
  275. : GrSamplerState::ClampNearest();
  276. flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make(
  277. *target->caps().shaderCaps(), this->color(), false, proxies, numActiveProxies,
  278. samplerState, maskFormat, localMatrix, vmPerspective);
  279. }
  280. flushInfo.fGlyphsToFlush = 0;
  281. size_t vertexStride = flushInfo.fGeometryProcessor->vertexStride();
  282. int glyphCount = this->numGlyphs();
  283. void* vertices = target->makeVertexSpace(vertexStride, glyphCount * kVerticesPerGlyph,
  284. &flushInfo.fVertexBuffer, &flushInfo.fVertexOffset);
  285. flushInfo.fIndexBuffer = resourceProvider->refQuadIndexBuffer();
  286. if (!vertices || !flushInfo.fVertexBuffer) {
  287. SkDebugf("Could not allocate vertices\n");
  288. return;
  289. }
  290. char* currVertex = reinterpret_cast<char*>(vertices);
  291. SkExclusiveStrikePtr autoGlyphCache;
  292. // each of these is a SubRun
  293. for (int i = 0; i < fGeoCount; i++) {
  294. const Geometry& args = fGeoData[i];
  295. Blob* blob = args.fBlob;
  296. // TODO4F: Preserve float colors
  297. GrTextBlob::VertexRegenerator regenerator(
  298. resourceProvider, blob, args.fRun, args.fSubRun, args.fViewMatrix, args.fX, args.fY,
  299. args.fColor.toBytes_RGBA(), target->deferredUploadTarget(), glyphCache,
  300. atlasManager, &autoGlyphCache);
  301. bool done = false;
  302. while (!done) {
  303. GrTextBlob::VertexRegenerator::Result result;
  304. if (!regenerator.regenerate(&result)) {
  305. break;
  306. }
  307. done = result.fFinished;
  308. // Copy regenerated vertices from the blob to our vertex buffer.
  309. size_t vertexBytes = result.fGlyphsRegenerated * kVerticesPerGlyph * vertexStride;
  310. if (args.fClipRect.isEmpty()) {
  311. memcpy(currVertex, result.fFirstVertex, vertexBytes);
  312. } else {
  313. SkASSERT(!vmPerspective);
  314. clip_quads(args.fClipRect, currVertex, result.fFirstVertex, vertexStride,
  315. result.fGlyphsRegenerated);
  316. }
  317. if (fNeedsGlyphTransform && !args.fViewMatrix.isIdentity()) {
  318. // We always do the distance field view matrix transformation after copying rather
  319. // than during blob vertex generation time in the blob as handling successive
  320. // arbitrary transformations would be complicated and accumulate error.
  321. if (args.fViewMatrix.hasPerspective()) {
  322. auto* pos = reinterpret_cast<SkPoint3*>(currVertex);
  323. SkMatrixPriv::MapHomogeneousPointsWithStride(
  324. args.fViewMatrix, pos, vertexStride, pos, vertexStride,
  325. result.fGlyphsRegenerated * kVerticesPerGlyph);
  326. } else {
  327. auto* pos = reinterpret_cast<SkPoint*>(currVertex);
  328. SkMatrixPriv::MapPointsWithStride(
  329. args.fViewMatrix, pos, vertexStride,
  330. result.fGlyphsRegenerated * kVerticesPerGlyph);
  331. }
  332. }
  333. flushInfo.fGlyphsToFlush += result.fGlyphsRegenerated;
  334. if (!result.fFinished) {
  335. this->flush(target, &flushInfo);
  336. }
  337. currVertex += vertexBytes;
  338. }
  339. }
  340. this->flush(target, &flushInfo);
  341. }
  342. void GrAtlasTextOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
  343. flushState->executeDrawsAndUploadsForMeshDrawOp(
  344. this, chainBounds, std::move(fProcessors), GrPipeline::InputFlags::kNone);
  345. }
  346. void GrAtlasTextOp::flush(GrMeshDrawOp::Target* target, FlushInfo* flushInfo) const {
  347. if (!flushInfo->fGlyphsToFlush) {
  348. return;
  349. }
  350. auto atlasManager = target->atlasManager();
  351. GrGeometryProcessor* gp = flushInfo->fGeometryProcessor.get();
  352. GrMaskFormat maskFormat = this->maskFormat();
  353. unsigned int numActiveProxies;
  354. const sk_sp<GrTextureProxy>* proxies = atlasManager->getProxies(maskFormat, &numActiveProxies);
  355. SkASSERT(proxies);
  356. if (gp->numTextureSamplers() != (int) numActiveProxies) {
  357. // During preparation the number of atlas pages has increased.
  358. // Update the proxies used in the GP to match.
  359. for (unsigned i = gp->numTextureSamplers(); i < numActiveProxies; ++i) {
  360. flushInfo->fFixedDynamicState->fPrimitiveProcessorTextures[i] = proxies[i].get();
  361. }
  362. if (this->usesDistanceFields()) {
  363. if (this->isLCD()) {
  364. reinterpret_cast<GrDistanceFieldLCDTextGeoProc*>(gp)->addNewProxies(
  365. proxies, numActiveProxies, GrSamplerState::ClampBilerp());
  366. } else {
  367. reinterpret_cast<GrDistanceFieldA8TextGeoProc*>(gp)->addNewProxies(
  368. proxies, numActiveProxies, GrSamplerState::ClampBilerp());
  369. }
  370. } else {
  371. GrSamplerState samplerState = fNeedsGlyphTransform ? GrSamplerState::ClampBilerp()
  372. : GrSamplerState::ClampNearest();
  373. reinterpret_cast<GrBitmapTextGeoProc*>(gp)->addNewProxies(proxies, numActiveProxies,
  374. samplerState);
  375. }
  376. }
  377. int maxGlyphsPerDraw = static_cast<int>(flushInfo->fIndexBuffer->size() / sizeof(uint16_t) / 6);
  378. GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
  379. mesh->setIndexedPatterned(flushInfo->fIndexBuffer, kIndicesPerGlyph, kVerticesPerGlyph,
  380. flushInfo->fGlyphsToFlush, maxGlyphsPerDraw);
  381. mesh->setVertexData(flushInfo->fVertexBuffer, flushInfo->fVertexOffset);
  382. target->recordDraw(
  383. flushInfo->fGeometryProcessor, mesh, 1, flushInfo->fFixedDynamicState, nullptr);
  384. flushInfo->fVertexOffset += kVerticesPerGlyph * flushInfo->fGlyphsToFlush;
  385. flushInfo->fGlyphsToFlush = 0;
  386. }
  387. GrOp::CombineResult GrAtlasTextOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
  388. GrAtlasTextOp* that = t->cast<GrAtlasTextOp>();
  389. if (fProcessors != that->fProcessors) {
  390. return CombineResult::kCannotCombine;
  391. }
  392. if (fMaskType != that->fMaskType) {
  393. return CombineResult::kCannotCombine;
  394. }
  395. const SkMatrix& thisFirstMatrix = fGeoData[0].fViewMatrix;
  396. const SkMatrix& thatFirstMatrix = that->fGeoData[0].fViewMatrix;
  397. if (this->usesLocalCoords() && !thisFirstMatrix.cheapEqualTo(thatFirstMatrix)) {
  398. return CombineResult::kCannotCombine;
  399. }
  400. if (fNeedsGlyphTransform != that->fNeedsGlyphTransform) {
  401. return CombineResult::kCannotCombine;
  402. }
  403. if (fNeedsGlyphTransform &&
  404. (thisFirstMatrix.hasPerspective() != thatFirstMatrix.hasPerspective())) {
  405. return CombineResult::kCannotCombine;
  406. }
  407. if (this->usesDistanceFields()) {
  408. if (fDFGPFlags != that->fDFGPFlags) {
  409. return CombineResult::kCannotCombine;
  410. }
  411. if (fLuminanceColor != that->fLuminanceColor) {
  412. return CombineResult::kCannotCombine;
  413. }
  414. } else {
  415. if (kColorBitmapMask_MaskType == fMaskType && this->color() != that->color()) {
  416. return CombineResult::kCannotCombine;
  417. }
  418. }
  419. // Keep the batch vertex buffer size below 32K so we don't have to create a special one
  420. // We use the largest possible vertex size for this
  421. static const int kVertexSize = sizeof(SkPoint) + sizeof(SkColor) + 2 * sizeof(uint16_t);
  422. static const int kMaxGlyphs = 32768 / (kVerticesPerGlyph * kVertexSize);
  423. if (this->fNumGlyphs + that->fNumGlyphs > kMaxGlyphs) {
  424. return CombineResult::kCannotCombine;
  425. }
  426. fNumGlyphs += that->numGlyphs();
  427. // Reallocate space for geo data if necessary and then import that geo's data.
  428. int newGeoCount = that->fGeoCount + fGeoCount;
  429. // We reallocate at a rate of 1.5x to try to get better total memory usage
  430. if (newGeoCount > fGeoDataAllocSize) {
  431. int newAllocSize = fGeoDataAllocSize + fGeoDataAllocSize / 2;
  432. while (newAllocSize < newGeoCount) {
  433. newAllocSize += newAllocSize / 2;
  434. }
  435. fGeoData.realloc(newAllocSize);
  436. fGeoDataAllocSize = newAllocSize;
  437. }
  438. // We steal the ref on the blobs from the other AtlasTextOp and set its count to 0 so that
  439. // it doesn't try to unref them.
  440. memcpy(&fGeoData[fGeoCount], that->fGeoData.get(), that->fGeoCount * sizeof(Geometry));
  441. #ifdef SK_DEBUG
  442. for (int i = 0; i < that->fGeoCount; ++i) {
  443. that->fGeoData.get()[i].fBlob = (Blob*)0x1;
  444. }
  445. #endif
  446. that->fGeoCount = 0;
  447. fGeoCount = newGeoCount;
  448. return CombineResult::kMerged;
  449. }
  450. // TODO trying to figure out why lcd is so whack
  451. // (see comments in GrTextContext::ComputeCanonicalColor)
  452. sk_sp<GrGeometryProcessor> GrAtlasTextOp::setupDfProcessor(const GrShaderCaps& caps,
  453. const sk_sp<GrTextureProxy>* proxies,
  454. unsigned int numActiveProxies) const {
  455. bool isLCD = this->isLCD();
  456. SkMatrix localMatrix = SkMatrix::I();
  457. if (this->usesLocalCoords()) {
  458. // If this fails we'll just use I().
  459. bool result = fGeoData[0].fViewMatrix.invert(&localMatrix);
  460. (void)result;
  461. }
  462. // see if we need to create a new effect
  463. if (isLCD) {
  464. float redCorrection = fDistanceAdjustTable->getAdjustment(
  465. SkColorGetR(fLuminanceColor) >> kDistanceAdjustLumShift,
  466. fUseGammaCorrectDistanceTable);
  467. float greenCorrection = fDistanceAdjustTable->getAdjustment(
  468. SkColorGetG(fLuminanceColor) >> kDistanceAdjustLumShift,
  469. fUseGammaCorrectDistanceTable);
  470. float blueCorrection = fDistanceAdjustTable->getAdjustment(
  471. SkColorGetB(fLuminanceColor) >> kDistanceAdjustLumShift,
  472. fUseGammaCorrectDistanceTable);
  473. GrDistanceFieldLCDTextGeoProc::DistanceAdjust widthAdjust =
  474. GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(
  475. redCorrection, greenCorrection, blueCorrection);
  476. return GrDistanceFieldLCDTextGeoProc::Make(caps, proxies, numActiveProxies,
  477. GrSamplerState::ClampBilerp(), widthAdjust,
  478. fDFGPFlags, localMatrix);
  479. } else {
  480. #ifdef SK_GAMMA_APPLY_TO_A8
  481. float correction = 0;
  482. if (kAliasedDistanceField_MaskType != fMaskType) {
  483. U8CPU lum = SkColorSpaceLuminance::computeLuminance(SK_GAMMA_EXPONENT,
  484. fLuminanceColor);
  485. correction = fDistanceAdjustTable->getAdjustment(lum >> kDistanceAdjustLumShift,
  486. fUseGammaCorrectDistanceTable);
  487. }
  488. return GrDistanceFieldA8TextGeoProc::Make(caps, proxies, numActiveProxies,
  489. GrSamplerState::ClampBilerp(),
  490. correction, fDFGPFlags, localMatrix);
  491. #else
  492. return GrDistanceFieldA8TextGeoProc::Make(caps, proxies, numActiveProxies,
  493. GrSamplerState::ClampBilerp(),
  494. fDFGPFlags, localMatrix);
  495. #endif
  496. }
  497. }