blob: c4c9170bde9f37c0af159f7c703c2c4f861a566f [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
Brian Salomon742e31d2016-12-07 17:06:19 -050010#include "GrOpFlushState.h"
joshualitta751c972015-11-20 13:37:32 -080011#include "GrResourceProvider.h"
12
joshualitta751c972015-11-20 13:37:32 -080013#include "SkGlyphCache.h"
halcanary4dbbd042016-06-07 17:21:10 -070014#include "SkMathPriv.h"
joshualitta751c972015-11-20 13:37:32 -080015
16#include "effects/GrBitmapTextGeoProc.h"
17#include "effects/GrDistanceFieldGeoProc.h"
Brian Salomonf856fd12016-12-16 14:24:34 -050018#include "text/GrAtlasGlyphCache.h"
joshualitta751c972015-11-20 13:37:32 -080019
joshualitt60ce86d2015-11-23 13:08:22 -080020///////////////////////////////////////////////////////////////////////////////////////////////////
21
joshualitta751c972015-11-20 13:37:32 -080022static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
23 unsigned r = SkColorGetR(c);
24 unsigned g = SkColorGetG(c);
25 unsigned b = SkColorGetB(c);
26 return GrColorPackRGBA(r, g, b, 0xff);
27}
28
29static const int kDistanceAdjustLumShift = 5;
30
Brian Salomon344ec422016-12-15 10:58:41 -050031SkString GrAtlasTextOp::dumpInfo() const {
joshualitta751c972015-11-20 13:37:32 -080032 SkString str;
33
34 for (int i = 0; i < fGeoCount; ++i) {
35 str.appendf("%d: Color: 0x%08x Trans: %.2f,%.2f Runs: %d\n",
36 i,
37 fGeoData[i].fColor,
joshualitt8e0ef292016-02-19 14:13:03 -080038 fGeoData[i].fX,
39 fGeoData[i].fY,
joshualittddd22d82016-02-16 06:47:52 -080040 fGeoData[i].fBlob->runCount());
joshualitta751c972015-11-20 13:37:32 -080041 }
42
Brian Salomon7c3e7182016-12-01 09:35:30 -050043 str.append(DumpPipelineInfo(*this->pipeline()));
joshualitta751c972015-11-20 13:37:32 -080044 str.append(INHERITED::dumpInfo());
45 return str;
46}
47
Brian Salomon92aee3d2016-12-21 09:20:25 -050048void GrAtlasTextOp::getPipelineAnalysisInput(GrPipelineAnalysisDrawOpInput* input) const {
joshualitta751c972015-11-20 13:37:32 -080049 if (kColorBitmapMask_MaskType == fMaskType) {
Brian Salomon92aee3d2016-12-21 09:20:25 -050050 input->pipelineColorInput()->setUnknownFourComponents();
joshualitta751c972015-11-20 13:37:32 -080051 } else {
Brian Salomon92aee3d2016-12-21 09:20:25 -050052 input->pipelineColorInput()->setKnownFourComponents(fColor);
joshualitta751c972015-11-20 13:37:32 -080053 }
joshualitta751c972015-11-20 13:37:32 -080054 switch (fMaskType) {
55 case kGrayscaleDistanceField_MaskType:
56 case kGrayscaleCoverageMask_MaskType:
Brian Salomon92aee3d2016-12-21 09:20:25 -050057 input->pipelineCoverageInput()->setUnknownSingleComponent();
joshualitta751c972015-11-20 13:37:32 -080058 break;
59 case kLCDCoverageMask_MaskType:
60 case kLCDDistanceField_MaskType:
Brian Salomon92aee3d2016-12-21 09:20:25 -050061 input->pipelineCoverageInput()->setUnknownOpaqueFourComponents();
62 input->pipelineCoverageInput()->setUsingLCDCoverage();
joshualitta751c972015-11-20 13:37:32 -080063 break;
64 case kColorBitmapMask_MaskType:
Brian Salomon92aee3d2016-12-21 09:20:25 -050065 input->pipelineCoverageInput()->setKnownSingleComponent(0xff);
joshualitta751c972015-11-20 13:37:32 -080066 }
67}
68
Brian Salomon92aee3d2016-12-21 09:20:25 -050069void GrAtlasTextOp::applyPipelineOptimizations(const GrPipelineOptimizations& optimizations) {
70 if (!optimizations.readsColor()) {
joshualitta751c972015-11-20 13:37:32 -080071 fGeoData[0].fColor = GrColor_ILLEGAL;
72 }
Brian Salomon92aee3d2016-12-21 09:20:25 -050073 optimizations.getOverrideColorIfSet(&fGeoData[0].fColor);
joshualitta751c972015-11-20 13:37:32 -080074
Brian Salomon92aee3d2016-12-21 09:20:25 -050075 fColorIgnored = !optimizations.readsColor();
Brian Salomon344ec422016-12-15 10:58:41 -050076 fColor = fGeoData[0].fColor;
Brian Salomon92aee3d2016-12-21 09:20:25 -050077 fUsesLocalCoords = optimizations.readsLocalCoords();
78 fCoverageIgnored = !optimizations.readsCoverage();
joshualitta751c972015-11-20 13:37:32 -080079}
80
Brian Salomon344ec422016-12-15 10:58:41 -050081void GrAtlasTextOp::onPrepareDraws(Target* target) const {
joshualitta751c972015-11-20 13:37:32 -080082 // if we have RGB, then we won't have any SkShaders so no need to use a localmatrix.
83 // TODO actually only invert if we don't have RGBA
84 SkMatrix localMatrix;
85 if (this->usesLocalCoords() && !this->viewMatrix().invert(&localMatrix)) {
86 SkDebugf("Cannot invert viewmatrix\n");
87 return;
88 }
89
90 GrTexture* texture = fFontCache->getTexture(this->maskFormat());
91 if (!texture) {
92 SkDebugf("Could not allocate backing texture for atlas\n");
93 return;
94 }
95
joshualitta751c972015-11-20 13:37:32 -080096 GrMaskFormat maskFormat = this->maskFormat();
joshualitta751c972015-11-20 13:37:32 -080097
bsalomon342bfc22016-04-01 06:06:20 -070098 FlushInfo flushInfo;
joshualittd9d30f72015-12-08 10:47:55 -080099 if (this->usesDistanceFields()) {
bungeman06ca8ec2016-06-09 08:01:03 -0700100 flushInfo.fGeometryProcessor =
Brian Salomon344ec422016-12-15 10:58:41 -0500101 this->setupDfProcessor(this->viewMatrix(), fFilteredColor, this->color(), texture);
joshualitta751c972015-11-20 13:37:32 -0800102 } else {
Brian Salomon514baff2016-11-17 15:17:07 -0500103 GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kNone_FilterMode);
Brian Salomon344ec422016-12-15 10:58:41 -0500104 flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make(
105 this->color(), texture, params, maskFormat, localMatrix, this->usesLocalCoords());
joshualitta751c972015-11-20 13:37:32 -0800106 }
107
joshualitta751c972015-11-20 13:37:32 -0800108 flushInfo.fGlyphsToFlush = 0;
bsalomon342bfc22016-04-01 06:06:20 -0700109 size_t vertexStride = flushInfo.fGeometryProcessor->getVertexStride();
joshualittf528e0d2015-12-09 06:42:52 -0800110 SkASSERT(vertexStride == GrAtlasTextBlob::GetVertexStride(maskFormat));
joshualitta751c972015-11-20 13:37:32 -0800111
joshualitta751c972015-11-20 13:37:32 -0800112 int glyphCount = this->numGlyphs();
cdalton397536c2016-03-25 12:15:03 -0700113 const GrBuffer* vertexBuffer;
joshualitta751c972015-11-20 13:37:32 -0800114
Brian Salomon344ec422016-12-15 10:58:41 -0500115 void* vertices = target->makeVertexSpace(
116 vertexStride, glyphCount * kVerticesPerGlyph, &vertexBuffer, &flushInfo.fVertexOffset);
joshualitta751c972015-11-20 13:37:32 -0800117 flushInfo.fVertexBuffer.reset(SkRef(vertexBuffer));
118 flushInfo.fIndexBuffer.reset(target->resourceProvider()->refQuadIndexBuffer());
119 if (!vertices || !flushInfo.fVertexBuffer) {
120 SkDebugf("Could not allocate vertices\n");
121 return;
122 }
123
124 unsigned char* currVertex = reinterpret_cast<unsigned char*>(vertices);
125
bsalomon342bfc22016-04-01 06:06:20 -0700126 GrBlobRegenHelper helper(this, target, &flushInfo);
bsalomond1c71fd2016-05-19 12:51:46 -0700127 SkAutoGlyphCache glyphCache;
joshualitta751c972015-11-20 13:37:32 -0800128 for (int i = 0; i < fGeoCount; i++) {
joshualitt144c3c82015-11-30 12:30:13 -0800129 const Geometry& args = fGeoData[i];
joshualitta751c972015-11-20 13:37:32 -0800130 Blob* blob = args.fBlob;
joshualittddd22d82016-02-16 06:47:52 -0800131 size_t byteCount;
132 void* blobVertices;
joshualitt8e0ef292016-02-19 14:13:03 -0800133 int subRunGlyphCount;
Brian Salomon09d994e2016-12-21 11:14:46 -0500134 blob->regenInOp(target, fFontCache, &helper, args.fRun, args.fSubRun, &glyphCache,
135 vertexStride, args.fViewMatrix, args.fX, args.fY, args.fColor,
136 &blobVertices, &byteCount, &subRunGlyphCount);
joshualitta751c972015-11-20 13:37:32 -0800137
138 // now copy all vertices
joshualittddd22d82016-02-16 06:47:52 -0800139 memcpy(currVertex, blobVertices, byteCount);
joshualitta751c972015-11-20 13:37:32 -0800140
joshualitt7481e752016-01-22 06:08:48 -0800141#ifdef SK_DEBUG
142 // bounds sanity check
143 SkRect rect;
144 rect.setLargestInverted();
Brian Salomon344ec422016-12-15 10:58:41 -0500145 SkPoint* vertex = (SkPoint*)((char*)blobVertices);
joshualitt8e0ef292016-02-19 14:13:03 -0800146 rect.growToInclude(vertex, vertexStride, kVerticesPerGlyph * subRunGlyphCount);
joshualitt7481e752016-01-22 06:08:48 -0800147
148 if (this->usesDistanceFields()) {
joshualitt8e0ef292016-02-19 14:13:03 -0800149 args.fViewMatrix.mapRect(&rect);
joshualitt7481e752016-01-22 06:08:48 -0800150 }
bsalomon33b6b8e2016-04-13 08:14:22 -0700151 // Allow for small numerical error in the bounds.
bsalomon88cf17d2016-07-08 06:40:56 -0700152 SkRect bounds = this->bounds();
bsalomon33b6b8e2016-04-13 08:14:22 -0700153 bounds.outset(0.001f, 0.001f);
154 SkASSERT(bounds.contains(rect));
joshualitt7481e752016-01-22 06:08:48 -0800155#endif
156
joshualitta751c972015-11-20 13:37:32 -0800157 currVertex += byteCount;
158 }
joshualitt60ce86d2015-11-23 13:08:22 -0800159
joshualitta751c972015-11-20 13:37:32 -0800160 this->flush(target, &flushInfo);
161}
162
Brian Salomon344ec422016-12-15 10:58:41 -0500163void GrAtlasTextOp::flush(GrMeshDrawOp::Target* target, FlushInfo* flushInfo) const {
egdaniel0e1853c2016-03-17 11:35:45 -0700164 GrMesh mesh;
cdalton397536c2016-03-25 12:15:03 -0700165 int maxGlyphsPerDraw =
Brian Salomon344ec422016-12-15 10:58:41 -0500166 static_cast<int>(flushInfo->fIndexBuffer->gpuMemorySize() / sizeof(uint16_t) / 6);
Hal Canary144caf52016-11-07 17:57:18 -0500167 mesh.initInstanced(kTriangles_GrPrimitiveType, flushInfo->fVertexBuffer.get(),
Brian Salomon344ec422016-12-15 10:58:41 -0500168 flushInfo->fIndexBuffer.get(), flushInfo->fVertexOffset, kVerticesPerGlyph,
169 kIndicesPerGlyph, flushInfo->fGlyphsToFlush, maxGlyphsPerDraw);
bungeman06ca8ec2016-06-09 08:01:03 -0700170 target->draw(flushInfo->fGeometryProcessor.get(), mesh);
joshualitta751c972015-11-20 13:37:32 -0800171 flushInfo->fVertexOffset += kVerticesPerGlyph * flushInfo->fGlyphsToFlush;
172 flushInfo->fGlyphsToFlush = 0;
173}
174
Brian Salomon344ec422016-12-15 10:58:41 -0500175bool GrAtlasTextOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
176 GrAtlasTextOp* that = t->cast<GrAtlasTextOp>();
joshualitta751c972015-11-20 13:37:32 -0800177 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
178 that->bounds(), caps)) {
179 return false;
180 }
181
182 if (fMaskType != that->fMaskType) {
183 return false;
184 }
185
186 if (!this->usesDistanceFields()) {
joshualittd9d30f72015-12-08 10:47:55 -0800187 if (kColorBitmapMask_MaskType == fMaskType && this->color() != that->color()) {
joshualitta751c972015-11-20 13:37:32 -0800188 return false;
189 }
190 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
191 return false;
192 }
193 } else {
194 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
195 return false;
196 }
197
198 if (fFilteredColor != that->fFilteredColor) {
199 return false;
200 }
201
202 if (fUseBGR != that->fUseBGR) {
203 return false;
204 }
joshualitta751c972015-11-20 13:37:32 -0800205 }
206
Brian Salomon344ec422016-12-15 10:58:41 -0500207 fNumGlyphs += that->numGlyphs();
joshualitta751c972015-11-20 13:37:32 -0800208
209 // Reallocate space for geo data if necessary and then import that's geo data.
210 int newGeoCount = that->fGeoCount + fGeoCount;
211 // We assume (and here enforce) that the allocation size is the smallest power of two that
212 // is greater than or equal to the number of geometries (and at least
213 // kMinGeometryAllocated).
214 int newAllocSize = GrNextPow2(newGeoCount);
215 int currAllocSize = SkTMax<int>(kMinGeometryAllocated, GrNextPow2(fGeoCount));
216
217 if (newGeoCount > currAllocSize) {
218 fGeoData.realloc(newAllocSize);
219 }
220
Brian Salomon344ec422016-12-15 10:58:41 -0500221 // 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 -0800222 // it doesn't try to unref them.
Brian Salomon344ec422016-12-15 10:58:41 -0500223 memcpy(&fGeoData[fGeoCount], that->fGeoData.get(), that->fGeoCount * sizeof(Geometry));
joshualitta751c972015-11-20 13:37:32 -0800224#ifdef SK_DEBUG
225 for (int i = 0; i < that->fGeoCount; ++i) {
226 that->fGeoData.get()[i].fBlob = (Blob*)0x1;
227 }
228#endif
229 that->fGeoCount = 0;
230 fGeoCount = newGeoCount;
231
bsalomon88cf17d2016-07-08 06:40:56 -0700232 this->joinBounds(*that);
joshualitta751c972015-11-20 13:37:32 -0800233 return true;
234}
235
236// TODO just use class params
237// TODO trying to figure out why lcd is so whack
Brian Salomon344ec422016-12-15 10:58:41 -0500238sk_sp<GrGeometryProcessor> GrAtlasTextOp::setupDfProcessor(const SkMatrix& viewMatrix,
239 SkColor filteredColor,
240 GrColor color,
241 GrTexture* texture) const {
Brian Salomon514baff2016-11-17 15:17:07 -0500242 GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kBilerp_FilterMode);
joshualitta751c972015-11-20 13:37:32 -0800243 bool isLCD = this->isLCD();
244 // set up any flags
245 uint32_t flags = viewMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
jvanverthcf371bb2016-03-10 11:10:43 -0800246 flags |= viewMatrix.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0;
brianosmanb461d342016-04-13 13:10:14 -0700247 flags |= fUseGammaCorrectDistanceTable ? kGammaCorrect_DistanceFieldEffectFlag : 0;
joshualitta751c972015-11-20 13:37:32 -0800248
249 // see if we need to create a new effect
250 if (isLCD) {
251 flags |= kUseLCD_DistanceFieldEffectFlag;
joshualitta751c972015-11-20 13:37:32 -0800252 flags |= fUseBGR ? kBGR_DistanceFieldEffectFlag : 0;
joshualitta751c972015-11-20 13:37:32 -0800253
254 GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor);
255
brianosman0586f5c2016-04-12 12:48:21 -0700256 float redCorrection = fDistanceAdjustTable->getAdjustment(
Brian Salomon344ec422016-12-15 10:58:41 -0500257 GrColorUnpackR(colorNoPreMul) >> kDistanceAdjustLumShift,
258 fUseGammaCorrectDistanceTable);
brianosman0586f5c2016-04-12 12:48:21 -0700259 float greenCorrection = fDistanceAdjustTable->getAdjustment(
Brian Salomon344ec422016-12-15 10:58:41 -0500260 GrColorUnpackG(colorNoPreMul) >> kDistanceAdjustLumShift,
261 fUseGammaCorrectDistanceTable);
brianosman0586f5c2016-04-12 12:48:21 -0700262 float blueCorrection = fDistanceAdjustTable->getAdjustment(
Brian Salomon344ec422016-12-15 10:58:41 -0500263 GrColorUnpackB(colorNoPreMul) >> kDistanceAdjustLumShift,
264 fUseGammaCorrectDistanceTable);
joshualitta751c972015-11-20 13:37:32 -0800265 GrDistanceFieldLCDTextGeoProc::DistanceAdjust widthAdjust =
Brian Salomon344ec422016-12-15 10:58:41 -0500266 GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(
267 redCorrection, greenCorrection, blueCorrection);
joshualitta751c972015-11-20 13:37:32 -0800268
Brian Salomon344ec422016-12-15 10:58:41 -0500269 return GrDistanceFieldLCDTextGeoProc::Make(
270 color, viewMatrix, texture, params, widthAdjust, flags, this->usesLocalCoords());
joshualitta751c972015-11-20 13:37:32 -0800271 } else {
joshualitta751c972015-11-20 13:37:32 -0800272#ifdef SK_GAMMA_APPLY_TO_A8
273 U8CPU lum = SkColorSpaceLuminance::computeLuminance(SK_GAMMA_EXPONENT, filteredColor);
Brian Salomon344ec422016-12-15 10:58:41 -0500274 float correction = fDistanceAdjustTable->getAdjustment(lum >> kDistanceAdjustLumShift,
275 fUseGammaCorrectDistanceTable);
276 return GrDistanceFieldA8TextGeoProc::Make(
277 color, viewMatrix, texture, params, correction, flags, this->usesLocalCoords());
joshualitta751c972015-11-20 13:37:32 -0800278#else
Brian Salomon344ec422016-12-15 10:58:41 -0500279 return GrDistanceFieldA8TextGeoProc::Make(
280 color, viewMatrix, texture, params, flags, this->usesLocalCoords());
joshualitta751c972015-11-20 13:37:32 -0800281#endif
282 }
joshualitta751c972015-11-20 13:37:32 -0800283}
joshualittddd22d82016-02-16 06:47:52 -0800284
Brian Salomon344ec422016-12-15 10:58:41 -0500285void GrBlobRegenHelper::flush() { fOp->flush(fTarget, fFlushInfo); }