blob: 65b3c373f94bba2eca44d43eadc1a304aea38c84 [file] [log] [blame]
joshualitta751c972015-11-20 13:37:32 -08001/*
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
Brian Salomon09e019e2016-12-15 10:20:35 -05008#include "GrAtlasTextOp.h"
joshualitta751c972015-11-20 13:37:32 -08009
Robert Phillips296b1cc2017-03-15 10:42:12 -040010#include "GrContext.h"
Brian Salomon742e31d2016-12-07 17:06:19 -050011#include "GrOpFlushState.h"
joshualitta751c972015-11-20 13:37:32 -080012#include "GrResourceProvider.h"
13
joshualitta751c972015-11-20 13:37:32 -080014#include "SkGlyphCache.h"
halcanary4dbbd042016-06-07 17:21:10 -070015#include "SkMathPriv.h"
joshualitta751c972015-11-20 13:37:32 -080016
17#include "effects/GrBitmapTextGeoProc.h"
18#include "effects/GrDistanceFieldGeoProc.h"
Brian Salomonf856fd12016-12-16 14:24:34 -050019#include "text/GrAtlasGlyphCache.h"
joshualitta751c972015-11-20 13:37:32 -080020
joshualitt60ce86d2015-11-23 13:08:22 -080021///////////////////////////////////////////////////////////////////////////////////////////////////
22
joshualitta751c972015-11-20 13:37:32 -080023static const int kDistanceAdjustLumShift = 5;
24
Brian Salomon344ec422016-12-15 10:58:41 -050025SkString GrAtlasTextOp::dumpInfo() const {
joshualitta751c972015-11-20 13:37:32 -080026 SkString str;
27
28 for (int i = 0; i < fGeoCount; ++i) {
29 str.appendf("%d: Color: 0x%08x Trans: %.2f,%.2f Runs: %d\n",
30 i,
31 fGeoData[i].fColor,
joshualitt8e0ef292016-02-19 14:13:03 -080032 fGeoData[i].fX,
33 fGeoData[i].fY,
joshualittddd22d82016-02-16 06:47:52 -080034 fGeoData[i].fBlob->runCount());
joshualitta751c972015-11-20 13:37:32 -080035 }
36
Brian Salomon44acb5b2017-07-18 19:59:24 -040037 str += fProcessors.dumpProcessors();
38 str += INHERITED::dumpInfo();
joshualitta751c972015-11-20 13:37:32 -080039 return str;
40}
41
Brian Salomon44acb5b2017-07-18 19:59:24 -040042GrDrawOp::FixedFunctionFlags GrAtlasTextOp::fixedFunctionFlags() const {
43 return FixedFunctionFlags::kNone;
44}
45
46GrDrawOp::RequiresDstTexture GrAtlasTextOp::finalize(const GrCaps& caps,
47 const GrAppliedClip* clip) {
48 GrProcessorAnalysisCoverage coverage;
49 GrProcessorAnalysisColor color;
joshualitta751c972015-11-20 13:37:32 -080050 if (kColorBitmapMask_MaskType == fMaskType) {
Brian Salomon44acb5b2017-07-18 19:59:24 -040051 color.setToUnknown();
joshualitta751c972015-11-20 13:37:32 -080052 } else {
Brian Salomon44acb5b2017-07-18 19:59:24 -040053 color.setToConstant(fColor);
joshualitta751c972015-11-20 13:37:32 -080054 }
joshualitta751c972015-11-20 13:37:32 -080055 switch (fMaskType) {
joshualitta751c972015-11-20 13:37:32 -080056 case kGrayscaleCoverageMask_MaskType:
Jim Van Verth90e89b32017-07-06 16:36:55 -040057 case kAliasedDistanceField_MaskType:
58 case kGrayscaleDistanceField_MaskType:
Brian Salomon44acb5b2017-07-18 19:59:24 -040059 coverage = GrProcessorAnalysisCoverage::kSingleChannel;
joshualitta751c972015-11-20 13:37:32 -080060 break;
61 case kLCDCoverageMask_MaskType:
62 case kLCDDistanceField_MaskType:
Jim Van Verth90e89b32017-07-06 16:36:55 -040063 case kLCDBGRDistanceField_MaskType:
Brian Salomon44acb5b2017-07-18 19:59:24 -040064 coverage = GrProcessorAnalysisCoverage::kLCD;
joshualitta751c972015-11-20 13:37:32 -080065 break;
66 case kColorBitmapMask_MaskType:
Brian Salomon44acb5b2017-07-18 19:59:24 -040067 coverage = GrProcessorAnalysisCoverage::kNone;
Brian Salomonc0b642c2017-03-27 13:09:36 -040068 break;
joshualitta751c972015-11-20 13:37:32 -080069 }
Brian Salomon44acb5b2017-07-18 19:59:24 -040070 auto analysis = fProcessors.finalize(color, coverage, clip, false, caps, &fColor);
71 fUsesLocalCoords = analysis.usesLocalCoords();
72 fCanCombineOnTouchOrOverlap =
73 !analysis.requiresDstTexture() &&
74 !(fProcessors.xferProcessor() && fProcessors.xferProcessor()->xferBarrierType(caps));
75 return analysis.requiresDstTexture() ? RequiresDstTexture::kYes : RequiresDstTexture::kNo;
joshualitta751c972015-11-20 13:37:32 -080076}
77
Brian Salomon91326c32017-08-09 16:02:19 -040078void GrAtlasTextOp::onPrepareDraws(Target* target) {
joshualitta751c972015-11-20 13:37:32 -080079 // if we have RGB, then we won't have any SkShaders so no need to use a localmatrix.
80 // TODO actually only invert if we don't have RGBA
81 SkMatrix localMatrix;
82 if (this->usesLocalCoords() && !this->viewMatrix().invert(&localMatrix)) {
83 SkDebugf("Cannot invert viewmatrix\n");
84 return;
85 }
86
Jim Van Vertheafa64b2017-09-18 10:05:00 -040087 GrMaskFormat maskFormat = this->maskFormat();
88
89 uint32_t atlasPageCount = fFontCache->getAtlasPageCount(maskFormat);
90 const sk_sp<GrTextureProxy>* proxies = fFontCache->getProxies(maskFormat);
91 if (!atlasPageCount || !proxies[0]) {
joshualitta751c972015-11-20 13:37:32 -080092 SkDebugf("Could not allocate backing texture for atlas\n");
93 return;
94 }
95
bsalomon342bfc22016-04-01 06:06:20 -070096 FlushInfo flushInfo;
Brian Salomonbfd18cd2017-08-09 16:27:09 -040097 flushInfo.fPipeline =
98 target->makePipeline(fSRGBFlags, std::move(fProcessors), target->detachAppliedClip());
joshualittd9d30f72015-12-08 10:47:55 -080099 if (this->usesDistanceFields()) {
bungeman06ca8ec2016-06-09 08:01:03 -0700100 flushInfo.fGeometryProcessor =
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400101 this->setupDfProcessor(this->viewMatrix(),
102 fLuminanceColor, this->color(), proxies);
joshualitta751c972015-11-20 13:37:32 -0800103 } else {
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400104 flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make(
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400105 this->color(), proxies, GrSamplerState::ClampNearest(), maskFormat,
106 localMatrix, this->usesLocalCoords());
joshualitta751c972015-11-20 13:37:32 -0800107 }
108
joshualitta751c972015-11-20 13:37:32 -0800109 flushInfo.fGlyphsToFlush = 0;
bsalomon342bfc22016-04-01 06:06:20 -0700110 size_t vertexStride = flushInfo.fGeometryProcessor->getVertexStride();
joshualittf528e0d2015-12-09 06:42:52 -0800111 SkASSERT(vertexStride == GrAtlasTextBlob::GetVertexStride(maskFormat));
joshualitta751c972015-11-20 13:37:32 -0800112
joshualitta751c972015-11-20 13:37:32 -0800113 int glyphCount = this->numGlyphs();
cdalton397536c2016-03-25 12:15:03 -0700114 const GrBuffer* vertexBuffer;
joshualitta751c972015-11-20 13:37:32 -0800115
Brian Salomon344ec422016-12-15 10:58:41 -0500116 void* vertices = target->makeVertexSpace(
117 vertexStride, glyphCount * kVerticesPerGlyph, &vertexBuffer, &flushInfo.fVertexOffset);
joshualitta751c972015-11-20 13:37:32 -0800118 flushInfo.fVertexBuffer.reset(SkRef(vertexBuffer));
119 flushInfo.fIndexBuffer.reset(target->resourceProvider()->refQuadIndexBuffer());
120 if (!vertices || !flushInfo.fVertexBuffer) {
121 SkDebugf("Could not allocate vertices\n");
122 return;
123 }
124
125 unsigned char* currVertex = reinterpret_cast<unsigned char*>(vertices);
126
bsalomon342bfc22016-04-01 06:06:20 -0700127 GrBlobRegenHelper helper(this, target, &flushInfo);
bsalomond1c71fd2016-05-19 12:51:46 -0700128 SkAutoGlyphCache glyphCache;
joshualitta751c972015-11-20 13:37:32 -0800129 for (int i = 0; i < fGeoCount; i++) {
joshualitt144c3c82015-11-30 12:30:13 -0800130 const Geometry& args = fGeoData[i];
joshualitta751c972015-11-20 13:37:32 -0800131 Blob* blob = args.fBlob;
joshualittddd22d82016-02-16 06:47:52 -0800132 size_t byteCount;
133 void* blobVertices;
joshualitt8e0ef292016-02-19 14:13:03 -0800134 int subRunGlyphCount;
Brian Salomon09d994e2016-12-21 11:14:46 -0500135 blob->regenInOp(target, fFontCache, &helper, args.fRun, args.fSubRun, &glyphCache,
136 vertexStride, args.fViewMatrix, args.fX, args.fY, args.fColor,
137 &blobVertices, &byteCount, &subRunGlyphCount);
joshualitta751c972015-11-20 13:37:32 -0800138
139 // now copy all vertices
joshualittddd22d82016-02-16 06:47:52 -0800140 memcpy(currVertex, blobVertices, byteCount);
joshualitta751c972015-11-20 13:37:32 -0800141
142 currVertex += byteCount;
143 }
joshualitt60ce86d2015-11-23 13:08:22 -0800144
joshualitta751c972015-11-20 13:37:32 -0800145 this->flush(target, &flushInfo);
146}
147
Brian Salomone5b399e2017-07-19 13:50:54 -0400148void GrAtlasTextOp::flush(GrMeshDrawOp::Target* target, FlushInfo* flushInfo) const {
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400149 GrGeometryProcessor* gp = flushInfo->fGeometryProcessor.get();
150 GrMaskFormat maskFormat = this->maskFormat();
151 if (gp->numTextureSamplers() != (int)fFontCache->getAtlasPageCount(maskFormat)) {
152 // During preparation the number of atlas pages has increased.
153 // Update the proxies used in the GP to match.
154 if (this->usesDistanceFields()) {
155 if (this->isLCD()) {
156 reinterpret_cast<GrDistanceFieldLCDTextGeoProc*>(gp)->addNewProxies(
157 fFontCache->getProxies(maskFormat), GrSamplerState::ClampBilerp());
158 } else {
159 reinterpret_cast<GrDistanceFieldA8TextGeoProc*>(gp)->addNewProxies(
160 fFontCache->getProxies(maskFormat), GrSamplerState::ClampBilerp());
161 }
162 } else {
163 reinterpret_cast<GrBitmapTextGeoProc*>(gp)->addNewProxies(
164 fFontCache->getProxies(maskFormat), GrSamplerState::ClampNearest());
165 }
166 }
167
Chris Dalton3809bab2017-06-13 10:55:06 -0600168 GrMesh mesh(GrPrimitiveType::kTriangles);
cdalton397536c2016-03-25 12:15:03 -0700169 int maxGlyphsPerDraw =
Brian Salomon344ec422016-12-15 10:58:41 -0500170 static_cast<int>(flushInfo->fIndexBuffer->gpuMemorySize() / sizeof(uint16_t) / 6);
Chris Dalton114a3c02017-05-26 15:17:19 -0600171 mesh.setIndexedPatterned(flushInfo->fIndexBuffer.get(), kIndicesPerGlyph, kVerticesPerGlyph,
Chris Daltonbca46e22017-05-15 11:03:26 -0600172 flushInfo->fGlyphsToFlush, maxGlyphsPerDraw);
Chris Dalton114a3c02017-05-26 15:17:19 -0600173 mesh.setVertexData(flushInfo->fVertexBuffer.get(), flushInfo->fVertexOffset);
Brian Salomon44acb5b2017-07-18 19:59:24 -0400174 target->draw(flushInfo->fGeometryProcessor.get(), flushInfo->fPipeline, mesh);
joshualitta751c972015-11-20 13:37:32 -0800175 flushInfo->fVertexOffset += kVerticesPerGlyph * flushInfo->fGlyphsToFlush;
176 flushInfo->fGlyphsToFlush = 0;
177}
178
Brian Salomon344ec422016-12-15 10:58:41 -0500179bool GrAtlasTextOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
180 GrAtlasTextOp* that = t->cast<GrAtlasTextOp>();
Brian Salomon44acb5b2017-07-18 19:59:24 -0400181 if (fProcessors != that->fProcessors) {
182 return false;
183 }
184
185 if (!fCanCombineOnTouchOrOverlap && GrRectsTouchOrOverlap(this->bounds(), that->bounds())) {
joshualitta751c972015-11-20 13:37:32 -0800186 return false;
187 }
188
189 if (fMaskType != that->fMaskType) {
190 return false;
191 }
192
193 if (!this->usesDistanceFields()) {
joshualittd9d30f72015-12-08 10:47:55 -0800194 if (kColorBitmapMask_MaskType == fMaskType && this->color() != that->color()) {
joshualitta751c972015-11-20 13:37:32 -0800195 return false;
196 }
197 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
198 return false;
199 }
200 } else {
201 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
202 return false;
203 }
204
Jim Van Verthbc2cdd12017-06-08 11:14:35 -0400205 if (fLuminanceColor != that->fLuminanceColor) {
joshualitta751c972015-11-20 13:37:32 -0800206 return false;
207 }
joshualitta751c972015-11-20 13:37:32 -0800208 }
209
Brian Salomon344ec422016-12-15 10:58:41 -0500210 fNumGlyphs += that->numGlyphs();
joshualitta751c972015-11-20 13:37:32 -0800211
212 // Reallocate space for geo data if necessary and then import that's geo data.
213 int newGeoCount = that->fGeoCount + fGeoCount;
214 // We assume (and here enforce) that the allocation size is the smallest power of two that
215 // is greater than or equal to the number of geometries (and at least
216 // kMinGeometryAllocated).
217 int newAllocSize = GrNextPow2(newGeoCount);
218 int currAllocSize = SkTMax<int>(kMinGeometryAllocated, GrNextPow2(fGeoCount));
219
220 if (newGeoCount > currAllocSize) {
221 fGeoData.realloc(newAllocSize);
222 }
223
Brian Salomon344ec422016-12-15 10:58:41 -0500224 // We steal the ref on the blobs from the other AtlasTextOp and set its count to 0 so that
joshualitta751c972015-11-20 13:37:32 -0800225 // it doesn't try to unref them.
Brian Salomon344ec422016-12-15 10:58:41 -0500226 memcpy(&fGeoData[fGeoCount], that->fGeoData.get(), that->fGeoCount * sizeof(Geometry));
joshualitta751c972015-11-20 13:37:32 -0800227#ifdef SK_DEBUG
228 for (int i = 0; i < that->fGeoCount; ++i) {
229 that->fGeoData.get()[i].fBlob = (Blob*)0x1;
230 }
231#endif
232 that->fGeoCount = 0;
233 fGeoCount = newGeoCount;
234
bsalomon88cf17d2016-07-08 06:40:56 -0700235 this->joinBounds(*that);
joshualitta751c972015-11-20 13:37:32 -0800236 return true;
237}
238
239// TODO just use class params
240// TODO trying to figure out why lcd is so whack
Jim Van Vertha950b632017-09-12 11:54:11 -0400241sk_sp<GrGeometryProcessor> GrAtlasTextOp::setupDfProcessor(
242 const SkMatrix& viewMatrix,
243 SkColor luminanceColor,
244 GrColor color,
245 const sk_sp<GrTextureProxy> p[kMaxTextures]) const {
joshualitta751c972015-11-20 13:37:32 -0800246 bool isLCD = this->isLCD();
247 // set up any flags
248 uint32_t flags = viewMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
jvanverthcf371bb2016-03-10 11:10:43 -0800249 flags |= viewMatrix.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0;
brianosmanb461d342016-04-13 13:10:14 -0700250 flags |= fUseGammaCorrectDistanceTable ? kGammaCorrect_DistanceFieldEffectFlag : 0;
Jim Van Verth90e89b32017-07-06 16:36:55 -0400251 flags |= (kAliasedDistanceField_MaskType == fMaskType) ? kAliased_DistanceFieldEffectFlag : 0;
joshualitta751c972015-11-20 13:37:32 -0800252
253 // see if we need to create a new effect
254 if (isLCD) {
255 flags |= kUseLCD_DistanceFieldEffectFlag;
Jim Van Verth90e89b32017-07-06 16:36:55 -0400256 flags |= (kLCDBGRDistanceField_MaskType == fMaskType) ? kBGR_DistanceFieldEffectFlag : 0;
joshualitta751c972015-11-20 13:37:32 -0800257
brianosman0586f5c2016-04-12 12:48:21 -0700258 float redCorrection = fDistanceAdjustTable->getAdjustment(
Jim Van Verthbc2cdd12017-06-08 11:14:35 -0400259 SkColorGetR(luminanceColor) >> kDistanceAdjustLumShift,
Brian Salomon344ec422016-12-15 10:58:41 -0500260 fUseGammaCorrectDistanceTable);
brianosman0586f5c2016-04-12 12:48:21 -0700261 float greenCorrection = fDistanceAdjustTable->getAdjustment(
Jim Van Verthbc2cdd12017-06-08 11:14:35 -0400262 SkColorGetG(luminanceColor) >> kDistanceAdjustLumShift,
Brian Salomon344ec422016-12-15 10:58:41 -0500263 fUseGammaCorrectDistanceTable);
brianosman0586f5c2016-04-12 12:48:21 -0700264 float blueCorrection = fDistanceAdjustTable->getAdjustment(
Jim Van Verthbc2cdd12017-06-08 11:14:35 -0400265 SkColorGetB(luminanceColor) >> kDistanceAdjustLumShift,
Brian Salomon344ec422016-12-15 10:58:41 -0500266 fUseGammaCorrectDistanceTable);
joshualitta751c972015-11-20 13:37:32 -0800267 GrDistanceFieldLCDTextGeoProc::DistanceAdjust widthAdjust =
Brian Salomon344ec422016-12-15 10:58:41 -0500268 GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(
269 redCorrection, greenCorrection, blueCorrection);
joshualitta751c972015-11-20 13:37:32 -0800270
Jim Van Vertha950b632017-09-12 11:54:11 -0400271 return GrDistanceFieldLCDTextGeoProc::Make(color, viewMatrix, p,
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400272 GrSamplerState::ClampBilerp(), widthAdjust,
273 flags, this->usesLocalCoords());
joshualitta751c972015-11-20 13:37:32 -0800274 } else {
joshualitta751c972015-11-20 13:37:32 -0800275#ifdef SK_GAMMA_APPLY_TO_A8
Jim Van Verth90e89b32017-07-06 16:36:55 -0400276 float correction = 0;
277 if (kAliasedDistanceField_MaskType != fMaskType) {
278 U8CPU lum = SkColorSpaceLuminance::computeLuminance(SK_GAMMA_EXPONENT, luminanceColor);
279 correction = fDistanceAdjustTable->getAdjustment(lum >> kDistanceAdjustLumShift,
280 fUseGammaCorrectDistanceTable);
281 }
Jim Van Vertha950b632017-09-12 11:54:11 -0400282 return GrDistanceFieldA8TextGeoProc::Make(color, viewMatrix, p,
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400283 GrSamplerState::ClampBilerp(), correction, flags,
284 this->usesLocalCoords());
joshualitta751c972015-11-20 13:37:32 -0800285#else
Jim Van Vertha950b632017-09-12 11:54:11 -0400286 return GrDistanceFieldA8TextGeoProc::Make(color, viewMatrix, p,
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400287 GrSamplerState::ClampBilerp(), flags,
288 this->usesLocalCoords());
joshualitta751c972015-11-20 13:37:32 -0800289#endif
290 }
joshualitta751c972015-11-20 13:37:32 -0800291}
joshualittddd22d82016-02-16 06:47:52 -0800292
Brian Salomon344ec422016-12-15 10:58:41 -0500293void GrBlobRegenHelper::flush() { fOp->flush(fTarget, fFlushInfo); }