blob: cf4ca24aa8076ad5aa67e0bbc03757475924e5a6 [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
8#include "GrAtlasTextBatch.h"
9
joshualitta751c972015-11-20 13:37:32 -080010#include "GrBatchFlushState.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"
joshualitte8042922015-12-11 06:11:21 -080018#include "text/GrBatchFontCache.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
31SkString GrAtlasTextBatch::dumpInfo() const {
32 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
halcanary9d524f22016-03-29 09:03:52 -070048void GrAtlasTextBatch::computePipelineOptimizations(GrInitInvariantOutput* color,
ethannicholasff210322015-11-24 12:10:10 -080049 GrInitInvariantOutput* coverage,
50 GrBatchToXPOverrides* overrides) const {
joshualitta751c972015-11-20 13:37:32 -080051 if (kColorBitmapMask_MaskType == fMaskType) {
ethannicholasff210322015-11-24 12:10:10 -080052 color->setUnknownFourComponents();
joshualitta751c972015-11-20 13:37:32 -080053 } else {
ethannicholasff210322015-11-24 12:10:10 -080054 color->setKnownFourComponents(fBatch.fColor);
joshualitta751c972015-11-20 13:37:32 -080055 }
joshualitta751c972015-11-20 13:37:32 -080056 switch (fMaskType) {
57 case kGrayscaleDistanceField_MaskType:
58 case kGrayscaleCoverageMask_MaskType:
ethannicholasff210322015-11-24 12:10:10 -080059 coverage->setUnknownSingleComponent();
joshualitta751c972015-11-20 13:37:32 -080060 break;
61 case kLCDCoverageMask_MaskType:
62 case kLCDDistanceField_MaskType:
ethannicholasff210322015-11-24 12:10:10 -080063 coverage->setUnknownOpaqueFourComponents();
64 coverage->setUsingLCDCoverage();
joshualitta751c972015-11-20 13:37:32 -080065 break;
66 case kColorBitmapMask_MaskType:
ethannicholasff210322015-11-24 12:10:10 -080067 coverage->setKnownSingleComponent(0xff);
joshualitta751c972015-11-20 13:37:32 -080068 }
69}
70
ethannicholasff210322015-11-24 12:10:10 -080071void GrAtlasTextBatch::initBatchTracker(const GrXPOverridesForBatch& overrides) {
joshualitta751c972015-11-20 13:37:32 -080072 // Handle any color overrides
ethannicholasff210322015-11-24 12:10:10 -080073 if (!overrides.readsColor()) {
joshualitta751c972015-11-20 13:37:32 -080074 fGeoData[0].fColor = GrColor_ILLEGAL;
75 }
ethannicholasff210322015-11-24 12:10:10 -080076 overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
joshualitta751c972015-11-20 13:37:32 -080077
78 // setup batch properties
ethannicholasff210322015-11-24 12:10:10 -080079 fBatch.fColorIgnored = !overrides.readsColor();
joshualitta751c972015-11-20 13:37:32 -080080 fBatch.fColor = fGeoData[0].fColor;
ethannicholasff210322015-11-24 12:10:10 -080081 fBatch.fUsesLocalCoords = overrides.readsLocalCoords();
82 fBatch.fCoverageIgnored = !overrides.readsCoverage();
joshualitta751c972015-11-20 13:37:32 -080083}
84
joshualitt144c3c82015-11-30 12:30:13 -080085void GrAtlasTextBatch::onPrepareDraws(Target* target) const {
joshualitta751c972015-11-20 13:37:32 -080086 // if we have RGB, then we won't have any SkShaders so no need to use a localmatrix.
87 // TODO actually only invert if we don't have RGBA
88 SkMatrix localMatrix;
89 if (this->usesLocalCoords() && !this->viewMatrix().invert(&localMatrix)) {
90 SkDebugf("Cannot invert viewmatrix\n");
91 return;
92 }
93
94 GrTexture* texture = fFontCache->getTexture(this->maskFormat());
95 if (!texture) {
96 SkDebugf("Could not allocate backing texture for atlas\n");
97 return;
98 }
99
joshualitta751c972015-11-20 13:37:32 -0800100 GrMaskFormat maskFormat = this->maskFormat();
joshualitta751c972015-11-20 13:37:32 -0800101
bsalomon342bfc22016-04-01 06:06:20 -0700102 FlushInfo flushInfo;
joshualittd9d30f72015-12-08 10:47:55 -0800103 if (this->usesDistanceFields()) {
bungeman06ca8ec2016-06-09 08:01:03 -0700104 flushInfo.fGeometryProcessor =
105 this->setupDfProcessor(this->viewMatrix(), fFilteredColor, this->color(), texture);
joshualitta751c972015-11-20 13:37:32 -0800106 } else {
Brian Salomon514baff2016-11-17 15:17:07 -0500107 GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kNone_FilterMode);
bungeman06ca8ec2016-06-09 08:01:03 -0700108 flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make(this->color(),
109 texture,
110 params,
111 maskFormat,
112 localMatrix,
113 this->usesLocalCoords());
joshualitta751c972015-11-20 13:37:32 -0800114 }
115
joshualitta751c972015-11-20 13:37:32 -0800116 flushInfo.fGlyphsToFlush = 0;
bsalomon342bfc22016-04-01 06:06:20 -0700117 size_t vertexStride = flushInfo.fGeometryProcessor->getVertexStride();
joshualittf528e0d2015-12-09 06:42:52 -0800118 SkASSERT(vertexStride == GrAtlasTextBlob::GetVertexStride(maskFormat));
joshualitta751c972015-11-20 13:37:32 -0800119
joshualitta751c972015-11-20 13:37:32 -0800120 int glyphCount = this->numGlyphs();
cdalton397536c2016-03-25 12:15:03 -0700121 const GrBuffer* vertexBuffer;
joshualitta751c972015-11-20 13:37:32 -0800122
123 void* vertices = target->makeVertexSpace(vertexStride,
124 glyphCount * kVerticesPerGlyph,
125 &vertexBuffer,
126 &flushInfo.fVertexOffset);
127 flushInfo.fVertexBuffer.reset(SkRef(vertexBuffer));
128 flushInfo.fIndexBuffer.reset(target->resourceProvider()->refQuadIndexBuffer());
129 if (!vertices || !flushInfo.fVertexBuffer) {
130 SkDebugf("Could not allocate vertices\n");
131 return;
132 }
133
134 unsigned char* currVertex = reinterpret_cast<unsigned char*>(vertices);
135
bsalomon342bfc22016-04-01 06:06:20 -0700136 GrBlobRegenHelper helper(this, target, &flushInfo);
bsalomond1c71fd2016-05-19 12:51:46 -0700137 SkAutoGlyphCache glyphCache;
joshualitta751c972015-11-20 13:37:32 -0800138 for (int i = 0; i < fGeoCount; i++) {
joshualitt144c3c82015-11-30 12:30:13 -0800139 const Geometry& args = fGeoData[i];
joshualitta751c972015-11-20 13:37:32 -0800140 Blob* blob = args.fBlob;
joshualittddd22d82016-02-16 06:47:52 -0800141 size_t byteCount;
142 void* blobVertices;
joshualitt8e0ef292016-02-19 14:13:03 -0800143 int subRunGlyphCount;
bsalomond1c71fd2016-05-19 12:51:46 -0700144 blob->regenInBatch(target, fFontCache, &helper, args.fRun, args.fSubRun, &glyphCache,
145 vertexStride, args.fViewMatrix, args.fX, args.fY, args.fColor,
146 &blobVertices, &byteCount, &subRunGlyphCount);
joshualitta751c972015-11-20 13:37:32 -0800147
148 // now copy all vertices
joshualittddd22d82016-02-16 06:47:52 -0800149 memcpy(currVertex, blobVertices, byteCount);
joshualitta751c972015-11-20 13:37:32 -0800150
joshualitt7481e752016-01-22 06:08:48 -0800151#ifdef SK_DEBUG
152 // bounds sanity check
153 SkRect rect;
154 rect.setLargestInverted();
joshualittddd22d82016-02-16 06:47:52 -0800155 SkPoint* vertex = (SkPoint*) ((char*)blobVertices);
joshualitt8e0ef292016-02-19 14:13:03 -0800156 rect.growToInclude(vertex, vertexStride, kVerticesPerGlyph * subRunGlyphCount);
joshualitt7481e752016-01-22 06:08:48 -0800157
158 if (this->usesDistanceFields()) {
joshualitt8e0ef292016-02-19 14:13:03 -0800159 args.fViewMatrix.mapRect(&rect);
joshualitt7481e752016-01-22 06:08:48 -0800160 }
bsalomon33b6b8e2016-04-13 08:14:22 -0700161 // Allow for small numerical error in the bounds.
bsalomon88cf17d2016-07-08 06:40:56 -0700162 SkRect bounds = this->bounds();
bsalomon33b6b8e2016-04-13 08:14:22 -0700163 bounds.outset(0.001f, 0.001f);
164 SkASSERT(bounds.contains(rect));
joshualitt7481e752016-01-22 06:08:48 -0800165#endif
166
joshualitta751c972015-11-20 13:37:32 -0800167 currVertex += byteCount;
168 }
joshualitt60ce86d2015-11-23 13:08:22 -0800169
joshualitta751c972015-11-20 13:37:32 -0800170 this->flush(target, &flushInfo);
171}
172
joshualitt144c3c82015-11-30 12:30:13 -0800173void GrAtlasTextBatch::flush(GrVertexBatch::Target* target, FlushInfo* flushInfo) const {
egdaniel0e1853c2016-03-17 11:35:45 -0700174 GrMesh mesh;
cdalton397536c2016-03-25 12:15:03 -0700175 int maxGlyphsPerDraw =
176 static_cast<int>(flushInfo->fIndexBuffer->gpuMemorySize() / sizeof(uint16_t) / 6);
Hal Canary144caf52016-11-07 17:57:18 -0500177 mesh.initInstanced(kTriangles_GrPrimitiveType, flushInfo->fVertexBuffer.get(),
178 flushInfo->fIndexBuffer.get(), flushInfo->fVertexOffset,
egdaniel0e1853c2016-03-17 11:35:45 -0700179 kVerticesPerGlyph, kIndicesPerGlyph, flushInfo->fGlyphsToFlush,
180 maxGlyphsPerDraw);
bungeman06ca8ec2016-06-09 08:01:03 -0700181 target->draw(flushInfo->fGeometryProcessor.get(), mesh);
joshualitta751c972015-11-20 13:37:32 -0800182 flushInfo->fVertexOffset += kVerticesPerGlyph * flushInfo->fGlyphsToFlush;
183 flushInfo->fGlyphsToFlush = 0;
184}
185
186bool GrAtlasTextBatch::onCombineIfPossible(GrBatch* t, const GrCaps& caps) {
187 GrAtlasTextBatch* that = t->cast<GrAtlasTextBatch>();
188 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
189 that->bounds(), caps)) {
190 return false;
191 }
192
193 if (fMaskType != that->fMaskType) {
194 return false;
195 }
196
197 if (!this->usesDistanceFields()) {
joshualittd9d30f72015-12-08 10:47:55 -0800198 if (kColorBitmapMask_MaskType == fMaskType && this->color() != that->color()) {
joshualitta751c972015-11-20 13:37:32 -0800199 return false;
200 }
201 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
202 return false;
203 }
204 } else {
205 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
206 return false;
207 }
208
209 if (fFilteredColor != that->fFilteredColor) {
210 return false;
211 }
212
213 if (fUseBGR != that->fUseBGR) {
214 return false;
215 }
joshualitta751c972015-11-20 13:37:32 -0800216 }
217
218 fBatch.fNumGlyphs += that->numGlyphs();
219
220 // Reallocate space for geo data if necessary and then import that's geo data.
221 int newGeoCount = that->fGeoCount + fGeoCount;
222 // We assume (and here enforce) that the allocation size is the smallest power of two that
223 // is greater than or equal to the number of geometries (and at least
224 // kMinGeometryAllocated).
225 int newAllocSize = GrNextPow2(newGeoCount);
226 int currAllocSize = SkTMax<int>(kMinGeometryAllocated, GrNextPow2(fGeoCount));
227
228 if (newGeoCount > currAllocSize) {
229 fGeoData.realloc(newAllocSize);
230 }
231
232 memcpy(&fGeoData[fGeoCount], that->fGeoData.get(), that->fGeoCount * sizeof(Geometry));
233 // We steal the ref on the blobs from the other TextBatch and set its count to 0 so that
234 // it doesn't try to unref them.
235#ifdef SK_DEBUG
236 for (int i = 0; i < that->fGeoCount; ++i) {
237 that->fGeoData.get()[i].fBlob = (Blob*)0x1;
238 }
239#endif
240 that->fGeoCount = 0;
241 fGeoCount = newGeoCount;
242
bsalomon88cf17d2016-07-08 06:40:56 -0700243 this->joinBounds(*that);
joshualitta751c972015-11-20 13:37:32 -0800244 return true;
245}
246
247// TODO just use class params
248// TODO trying to figure out why lcd is so whack
bungeman06ca8ec2016-06-09 08:01:03 -0700249sk_sp<GrGeometryProcessor> GrAtlasTextBatch::setupDfProcessor(const SkMatrix& viewMatrix,
250 SkColor filteredColor,
251 GrColor color,
252 GrTexture* texture) const {
Brian Salomon514baff2016-11-17 15:17:07 -0500253 GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kBilerp_FilterMode);
joshualitta751c972015-11-20 13:37:32 -0800254 bool isLCD = this->isLCD();
255 // set up any flags
256 uint32_t flags = viewMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
jvanverthcf371bb2016-03-10 11:10:43 -0800257 flags |= viewMatrix.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0;
brianosmanb461d342016-04-13 13:10:14 -0700258 flags |= fUseGammaCorrectDistanceTable ? kGammaCorrect_DistanceFieldEffectFlag : 0;
joshualitta751c972015-11-20 13:37:32 -0800259
260 // see if we need to create a new effect
261 if (isLCD) {
262 flags |= kUseLCD_DistanceFieldEffectFlag;
joshualitta751c972015-11-20 13:37:32 -0800263 flags |= fUseBGR ? kBGR_DistanceFieldEffectFlag : 0;
joshualitta751c972015-11-20 13:37:32 -0800264
265 GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor);
266
brianosman0586f5c2016-04-12 12:48:21 -0700267 float redCorrection = fDistanceAdjustTable->getAdjustment(
brianosmanb461d342016-04-13 13:10:14 -0700268 GrColorUnpackR(colorNoPreMul) >> kDistanceAdjustLumShift,
269 fUseGammaCorrectDistanceTable);
brianosman0586f5c2016-04-12 12:48:21 -0700270 float greenCorrection = fDistanceAdjustTable->getAdjustment(
brianosmanb461d342016-04-13 13:10:14 -0700271 GrColorUnpackG(colorNoPreMul) >> kDistanceAdjustLumShift,
272 fUseGammaCorrectDistanceTable);
brianosman0586f5c2016-04-12 12:48:21 -0700273 float blueCorrection = fDistanceAdjustTable->getAdjustment(
brianosmanb461d342016-04-13 13:10:14 -0700274 GrColorUnpackB(colorNoPreMul) >> kDistanceAdjustLumShift,
275 fUseGammaCorrectDistanceTable);
joshualitta751c972015-11-20 13:37:32 -0800276 GrDistanceFieldLCDTextGeoProc::DistanceAdjust widthAdjust =
277 GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(redCorrection,
278 greenCorrection,
279 blueCorrection);
280
bungeman06ca8ec2016-06-09 08:01:03 -0700281 return GrDistanceFieldLCDTextGeoProc::Make(color,
282 viewMatrix,
283 texture,
284 params,
285 widthAdjust,
286 flags,
287 this->usesLocalCoords());
joshualitta751c972015-11-20 13:37:32 -0800288 } else {
joshualitta751c972015-11-20 13:37:32 -0800289#ifdef SK_GAMMA_APPLY_TO_A8
290 U8CPU lum = SkColorSpaceLuminance::computeLuminance(SK_GAMMA_EXPONENT, filteredColor);
brianosman0586f5c2016-04-12 12:48:21 -0700291 float correction = fDistanceAdjustTable->getAdjustment(
brianosmanb461d342016-04-13 13:10:14 -0700292 lum >> kDistanceAdjustLumShift, fUseGammaCorrectDistanceTable);
bungeman06ca8ec2016-06-09 08:01:03 -0700293 return GrDistanceFieldA8TextGeoProc::Make(color,
294 viewMatrix,
295 texture,
296 params,
297 correction,
298 flags,
299 this->usesLocalCoords());
joshualitta751c972015-11-20 13:37:32 -0800300#else
bungeman06ca8ec2016-06-09 08:01:03 -0700301 return GrDistanceFieldA8TextGeoProc::Make(color,
302 viewMatrix,
303 texture,
304 params,
305 flags,
306 this->usesLocalCoords());
joshualitta751c972015-11-20 13:37:32 -0800307#endif
308 }
309
310}
joshualittddd22d82016-02-16 06:47:52 -0800311
312void GrBlobRegenHelper::flush() {
313 fBatch->flush(fTarget, fFlushInfo);
joshualittddd22d82016-02-16 06:47:52 -0800314}