blob: 1c67fe7db917feb88197f094669737098bec781c [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,
Brian Osman9a725dd2017-09-20 09:53:22 -040047 const GrAppliedClip* clip,
48 GrPixelConfigIsClamped dstIsClamped) {
Brian Salomon44acb5b2017-07-18 19:59:24 -040049 GrProcessorAnalysisCoverage coverage;
50 GrProcessorAnalysisColor color;
joshualitta751c972015-11-20 13:37:32 -080051 if (kColorBitmapMask_MaskType == fMaskType) {
Brian Salomon44acb5b2017-07-18 19:59:24 -040052 color.setToUnknown();
joshualitta751c972015-11-20 13:37:32 -080053 } else {
Brian Salomon44acb5b2017-07-18 19:59:24 -040054 color.setToConstant(fColor);
joshualitta751c972015-11-20 13:37:32 -080055 }
joshualitta751c972015-11-20 13:37:32 -080056 switch (fMaskType) {
joshualitta751c972015-11-20 13:37:32 -080057 case kGrayscaleCoverageMask_MaskType:
Jim Van Verth90e89b32017-07-06 16:36:55 -040058 case kAliasedDistanceField_MaskType:
59 case kGrayscaleDistanceField_MaskType:
Brian Salomon44acb5b2017-07-18 19:59:24 -040060 coverage = GrProcessorAnalysisCoverage::kSingleChannel;
joshualitta751c972015-11-20 13:37:32 -080061 break;
62 case kLCDCoverageMask_MaskType:
63 case kLCDDistanceField_MaskType:
Jim Van Verth90e89b32017-07-06 16:36:55 -040064 case kLCDBGRDistanceField_MaskType:
Brian Salomon44acb5b2017-07-18 19:59:24 -040065 coverage = GrProcessorAnalysisCoverage::kLCD;
joshualitta751c972015-11-20 13:37:32 -080066 break;
67 case kColorBitmapMask_MaskType:
Brian Salomon44acb5b2017-07-18 19:59:24 -040068 coverage = GrProcessorAnalysisCoverage::kNone;
Brian Salomonc0b642c2017-03-27 13:09:36 -040069 break;
joshualitta751c972015-11-20 13:37:32 -080070 }
Brian Osman9a725dd2017-09-20 09:53:22 -040071 auto analysis = fProcessors.finalize(color, coverage, clip, false, caps, dstIsClamped, &fColor);
Brian Salomon44acb5b2017-07-18 19:59:24 -040072 fUsesLocalCoords = analysis.usesLocalCoords();
73 fCanCombineOnTouchOrOverlap =
74 !analysis.requiresDstTexture() &&
75 !(fProcessors.xferProcessor() && fProcessors.xferProcessor()->xferBarrierType(caps));
76 return analysis.requiresDstTexture() ? RequiresDstTexture::kYes : RequiresDstTexture::kNo;
joshualitta751c972015-11-20 13:37:32 -080077}
78
Brian Salomon91326c32017-08-09 16:02:19 -040079void GrAtlasTextOp::onPrepareDraws(Target* target) {
joshualitta751c972015-11-20 13:37:32 -080080 // if we have RGB, then we won't have any SkShaders so no need to use a localmatrix.
81 // TODO actually only invert if we don't have RGBA
82 SkMatrix localMatrix;
83 if (this->usesLocalCoords() && !this->viewMatrix().invert(&localMatrix)) {
84 SkDebugf("Cannot invert viewmatrix\n");
85 return;
86 }
87
Jim Van Vertheafa64b2017-09-18 10:05:00 -040088 GrMaskFormat maskFormat = this->maskFormat();
89
90 uint32_t atlasPageCount = fFontCache->getAtlasPageCount(maskFormat);
91 const sk_sp<GrTextureProxy>* proxies = fFontCache->getProxies(maskFormat);
92 if (!atlasPageCount || !proxies[0]) {
joshualitta751c972015-11-20 13:37:32 -080093 SkDebugf("Could not allocate backing texture for atlas\n");
94 return;
95 }
96
bsalomon342bfc22016-04-01 06:06:20 -070097 FlushInfo flushInfo;
Brian Salomonbfd18cd2017-08-09 16:27:09 -040098 flushInfo.fPipeline =
99 target->makePipeline(fSRGBFlags, std::move(fProcessors), target->detachAppliedClip());
joshualittd9d30f72015-12-08 10:47:55 -0800100 if (this->usesDistanceFields()) {
bungeman06ca8ec2016-06-09 08:01:03 -0700101 flushInfo.fGeometryProcessor =
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400102 this->setupDfProcessor(this->viewMatrix(),
103 fLuminanceColor, this->color(), proxies);
joshualitta751c972015-11-20 13:37:32 -0800104 } else {
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400105 flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make(
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400106 this->color(), proxies, GrSamplerState::ClampNearest(), maskFormat,
107 localMatrix, this->usesLocalCoords());
joshualitta751c972015-11-20 13:37:32 -0800108 }
109
joshualitta751c972015-11-20 13:37:32 -0800110 flushInfo.fGlyphsToFlush = 0;
bsalomon342bfc22016-04-01 06:06:20 -0700111 size_t vertexStride = flushInfo.fGeometryProcessor->getVertexStride();
joshualittf528e0d2015-12-09 06:42:52 -0800112 SkASSERT(vertexStride == GrAtlasTextBlob::GetVertexStride(maskFormat));
joshualitta751c972015-11-20 13:37:32 -0800113
joshualitta751c972015-11-20 13:37:32 -0800114 int glyphCount = this->numGlyphs();
cdalton397536c2016-03-25 12:15:03 -0700115 const GrBuffer* vertexBuffer;
joshualitta751c972015-11-20 13:37:32 -0800116
Brian Salomon344ec422016-12-15 10:58:41 -0500117 void* vertices = target->makeVertexSpace(
118 vertexStride, glyphCount * kVerticesPerGlyph, &vertexBuffer, &flushInfo.fVertexOffset);
joshualitta751c972015-11-20 13:37:32 -0800119 flushInfo.fVertexBuffer.reset(SkRef(vertexBuffer));
Brian Salomond28a79d2017-10-16 13:01:07 -0400120 flushInfo.fIndexBuffer = target->resourceProvider()->refQuadIndexBuffer();
joshualitta751c972015-11-20 13:37:32 -0800121 if (!vertices || !flushInfo.fVertexBuffer) {
122 SkDebugf("Could not allocate vertices\n");
123 return;
124 }
125
126 unsigned char* currVertex = reinterpret_cast<unsigned char*>(vertices);
127
bsalomon342bfc22016-04-01 06:06:20 -0700128 GrBlobRegenHelper helper(this, target, &flushInfo);
bsalomond1c71fd2016-05-19 12:51:46 -0700129 SkAutoGlyphCache glyphCache;
joshualitta751c972015-11-20 13:37:32 -0800130 for (int i = 0; i < fGeoCount; i++) {
joshualitt144c3c82015-11-30 12:30:13 -0800131 const Geometry& args = fGeoData[i];
joshualitta751c972015-11-20 13:37:32 -0800132 Blob* blob = args.fBlob;
joshualittddd22d82016-02-16 06:47:52 -0800133 size_t byteCount;
134 void* blobVertices;
joshualitt8e0ef292016-02-19 14:13:03 -0800135 int subRunGlyphCount;
Brian Salomon09d994e2016-12-21 11:14:46 -0500136 blob->regenInOp(target, fFontCache, &helper, args.fRun, args.fSubRun, &glyphCache,
137 vertexStride, args.fViewMatrix, args.fX, args.fY, args.fColor,
138 &blobVertices, &byteCount, &subRunGlyphCount);
joshualitta751c972015-11-20 13:37:32 -0800139
140 // now copy all vertices
joshualittddd22d82016-02-16 06:47:52 -0800141 memcpy(currVertex, blobVertices, byteCount);
joshualitta751c972015-11-20 13:37:32 -0800142
143 currVertex += byteCount;
144 }
joshualitt60ce86d2015-11-23 13:08:22 -0800145
joshualitta751c972015-11-20 13:37:32 -0800146 this->flush(target, &flushInfo);
147}
148
Brian Salomone5b399e2017-07-19 13:50:54 -0400149void GrAtlasTextOp::flush(GrMeshDrawOp::Target* target, FlushInfo* flushInfo) const {
Jim Van Vertheafa64b2017-09-18 10:05:00 -0400150 GrGeometryProcessor* gp = flushInfo->fGeometryProcessor.get();
151 GrMaskFormat maskFormat = this->maskFormat();
152 if (gp->numTextureSamplers() != (int)fFontCache->getAtlasPageCount(maskFormat)) {
153 // During preparation the number of atlas pages has increased.
154 // Update the proxies used in the GP to match.
155 if (this->usesDistanceFields()) {
156 if (this->isLCD()) {
157 reinterpret_cast<GrDistanceFieldLCDTextGeoProc*>(gp)->addNewProxies(
158 fFontCache->getProxies(maskFormat), GrSamplerState::ClampBilerp());
159 } else {
160 reinterpret_cast<GrDistanceFieldA8TextGeoProc*>(gp)->addNewProxies(
161 fFontCache->getProxies(maskFormat), GrSamplerState::ClampBilerp());
162 }
163 } else {
164 reinterpret_cast<GrBitmapTextGeoProc*>(gp)->addNewProxies(
165 fFontCache->getProxies(maskFormat), GrSamplerState::ClampNearest());
166 }
167 }
168
Chris Dalton3809bab2017-06-13 10:55:06 -0600169 GrMesh mesh(GrPrimitiveType::kTriangles);
cdalton397536c2016-03-25 12:15:03 -0700170 int maxGlyphsPerDraw =
Brian Salomon344ec422016-12-15 10:58:41 -0500171 static_cast<int>(flushInfo->fIndexBuffer->gpuMemorySize() / sizeof(uint16_t) / 6);
Chris Dalton114a3c02017-05-26 15:17:19 -0600172 mesh.setIndexedPatterned(flushInfo->fIndexBuffer.get(), kIndicesPerGlyph, kVerticesPerGlyph,
Chris Daltonbca46e22017-05-15 11:03:26 -0600173 flushInfo->fGlyphsToFlush, maxGlyphsPerDraw);
Chris Dalton114a3c02017-05-26 15:17:19 -0600174 mesh.setVertexData(flushInfo->fVertexBuffer.get(), flushInfo->fVertexOffset);
Brian Salomon44acb5b2017-07-18 19:59:24 -0400175 target->draw(flushInfo->fGeometryProcessor.get(), flushInfo->fPipeline, mesh);
joshualitta751c972015-11-20 13:37:32 -0800176 flushInfo->fVertexOffset += kVerticesPerGlyph * flushInfo->fGlyphsToFlush;
177 flushInfo->fGlyphsToFlush = 0;
178}
179
Brian Salomon344ec422016-12-15 10:58:41 -0500180bool GrAtlasTextOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
181 GrAtlasTextOp* that = t->cast<GrAtlasTextOp>();
Brian Salomon44acb5b2017-07-18 19:59:24 -0400182 if (fProcessors != that->fProcessors) {
183 return false;
184 }
185
186 if (!fCanCombineOnTouchOrOverlap && GrRectsTouchOrOverlap(this->bounds(), that->bounds())) {
joshualitta751c972015-11-20 13:37:32 -0800187 return false;
188 }
189
190 if (fMaskType != that->fMaskType) {
191 return false;
192 }
193
194 if (!this->usesDistanceFields()) {
joshualittd9d30f72015-12-08 10:47:55 -0800195 if (kColorBitmapMask_MaskType == fMaskType && this->color() != that->color()) {
joshualitta751c972015-11-20 13:37:32 -0800196 return false;
197 }
198 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
199 return false;
200 }
201 } else {
202 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
203 return false;
204 }
205
Jim Van Verthbc2cdd12017-06-08 11:14:35 -0400206 if (fLuminanceColor != that->fLuminanceColor) {
joshualitta751c972015-11-20 13:37:32 -0800207 return false;
208 }
joshualitta751c972015-11-20 13:37:32 -0800209 }
210
Brian Salomon344ec422016-12-15 10:58:41 -0500211 fNumGlyphs += that->numGlyphs();
joshualitta751c972015-11-20 13:37:32 -0800212
213 // Reallocate space for geo data if necessary and then import that's geo data.
214 int newGeoCount = that->fGeoCount + fGeoCount;
215 // We assume (and here enforce) that the allocation size is the smallest power of two that
216 // is greater than or equal to the number of geometries (and at least
217 // kMinGeometryAllocated).
218 int newAllocSize = GrNextPow2(newGeoCount);
219 int currAllocSize = SkTMax<int>(kMinGeometryAllocated, GrNextPow2(fGeoCount));
220
221 if (newGeoCount > currAllocSize) {
222 fGeoData.realloc(newAllocSize);
223 }
224
Brian Salomon344ec422016-12-15 10:58:41 -0500225 // 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 -0800226 // it doesn't try to unref them.
Brian Salomon344ec422016-12-15 10:58:41 -0500227 memcpy(&fGeoData[fGeoCount], that->fGeoData.get(), that->fGeoCount * sizeof(Geometry));
joshualitta751c972015-11-20 13:37:32 -0800228#ifdef SK_DEBUG
229 for (int i = 0; i < that->fGeoCount; ++i) {
230 that->fGeoData.get()[i].fBlob = (Blob*)0x1;
231 }
232#endif
233 that->fGeoCount = 0;
234 fGeoCount = newGeoCount;
235
bsalomon88cf17d2016-07-08 06:40:56 -0700236 this->joinBounds(*that);
joshualitta751c972015-11-20 13:37:32 -0800237 return true;
238}
239
240// TODO just use class params
241// TODO trying to figure out why lcd is so whack
Jim Van Vertha950b632017-09-12 11:54:11 -0400242sk_sp<GrGeometryProcessor> GrAtlasTextOp::setupDfProcessor(
243 const SkMatrix& viewMatrix,
244 SkColor luminanceColor,
245 GrColor color,
246 const sk_sp<GrTextureProxy> p[kMaxTextures]) const {
joshualitta751c972015-11-20 13:37:32 -0800247 bool isLCD = this->isLCD();
248 // set up any flags
249 uint32_t flags = viewMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
jvanverthcf371bb2016-03-10 11:10:43 -0800250 flags |= viewMatrix.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0;
brianosmanb461d342016-04-13 13:10:14 -0700251 flags |= fUseGammaCorrectDistanceTable ? kGammaCorrect_DistanceFieldEffectFlag : 0;
Jim Van Verth90e89b32017-07-06 16:36:55 -0400252 flags |= (kAliasedDistanceField_MaskType == fMaskType) ? kAliased_DistanceFieldEffectFlag : 0;
joshualitta751c972015-11-20 13:37:32 -0800253
254 // see if we need to create a new effect
255 if (isLCD) {
256 flags |= kUseLCD_DistanceFieldEffectFlag;
Jim Van Verth90e89b32017-07-06 16:36:55 -0400257 flags |= (kLCDBGRDistanceField_MaskType == fMaskType) ? kBGR_DistanceFieldEffectFlag : 0;
joshualitta751c972015-11-20 13:37:32 -0800258
brianosman0586f5c2016-04-12 12:48:21 -0700259 float redCorrection = fDistanceAdjustTable->getAdjustment(
Jim Van Verthbc2cdd12017-06-08 11:14:35 -0400260 SkColorGetR(luminanceColor) >> kDistanceAdjustLumShift,
Brian Salomon344ec422016-12-15 10:58:41 -0500261 fUseGammaCorrectDistanceTable);
brianosman0586f5c2016-04-12 12:48:21 -0700262 float greenCorrection = fDistanceAdjustTable->getAdjustment(
Jim Van Verthbc2cdd12017-06-08 11:14:35 -0400263 SkColorGetG(luminanceColor) >> kDistanceAdjustLumShift,
Brian Salomon344ec422016-12-15 10:58:41 -0500264 fUseGammaCorrectDistanceTable);
brianosman0586f5c2016-04-12 12:48:21 -0700265 float blueCorrection = fDistanceAdjustTable->getAdjustment(
Jim Van Verthbc2cdd12017-06-08 11:14:35 -0400266 SkColorGetB(luminanceColor) >> kDistanceAdjustLumShift,
Brian Salomon344ec422016-12-15 10:58:41 -0500267 fUseGammaCorrectDistanceTable);
joshualitta751c972015-11-20 13:37:32 -0800268 GrDistanceFieldLCDTextGeoProc::DistanceAdjust widthAdjust =
Brian Salomon344ec422016-12-15 10:58:41 -0500269 GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(
270 redCorrection, greenCorrection, blueCorrection);
joshualitta751c972015-11-20 13:37:32 -0800271
Jim Van Vertha950b632017-09-12 11:54:11 -0400272 return GrDistanceFieldLCDTextGeoProc::Make(color, viewMatrix, p,
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400273 GrSamplerState::ClampBilerp(), widthAdjust,
274 flags, this->usesLocalCoords());
joshualitta751c972015-11-20 13:37:32 -0800275 } else {
joshualitta751c972015-11-20 13:37:32 -0800276#ifdef SK_GAMMA_APPLY_TO_A8
Jim Van Verth90e89b32017-07-06 16:36:55 -0400277 float correction = 0;
278 if (kAliasedDistanceField_MaskType != fMaskType) {
279 U8CPU lum = SkColorSpaceLuminance::computeLuminance(SK_GAMMA_EXPONENT, luminanceColor);
280 correction = fDistanceAdjustTable->getAdjustment(lum >> kDistanceAdjustLumShift,
281 fUseGammaCorrectDistanceTable);
282 }
Jim Van Vertha950b632017-09-12 11:54:11 -0400283 return GrDistanceFieldA8TextGeoProc::Make(color, viewMatrix, p,
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400284 GrSamplerState::ClampBilerp(), correction, flags,
285 this->usesLocalCoords());
joshualitta751c972015-11-20 13:37:32 -0800286#else
Jim Van Vertha950b632017-09-12 11:54:11 -0400287 return GrDistanceFieldA8TextGeoProc::Make(color, viewMatrix, p,
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400288 GrSamplerState::ClampBilerp(), flags,
289 this->usesLocalCoords());
joshualitta751c972015-11-20 13:37:32 -0800290#endif
291 }
joshualitta751c972015-11-20 13:37:32 -0800292}
joshualittddd22d82016-02-16 06:47:52 -0800293
Brian Salomon344ec422016-12-15 10:58:41 -0500294void GrBlobRegenHelper::flush() { fOp->flush(fTarget, fFlushInfo); }