blob: fe5c3b92e61994583b0baf72b5268de040fcaf89 [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
43 str.append(INHERITED::dumpInfo());
44 return str;
45}
46
halcanary9d524f22016-03-29 09:03:52 -070047void GrAtlasTextBatch::computePipelineOptimizations(GrInitInvariantOutput* color,
ethannicholasff210322015-11-24 12:10:10 -080048 GrInitInvariantOutput* coverage,
49 GrBatchToXPOverrides* overrides) const {
joshualitta751c972015-11-20 13:37:32 -080050 if (kColorBitmapMask_MaskType == fMaskType) {
ethannicholasff210322015-11-24 12:10:10 -080051 color->setUnknownFourComponents();
joshualitta751c972015-11-20 13:37:32 -080052 } else {
ethannicholasff210322015-11-24 12:10:10 -080053 color->setKnownFourComponents(fBatch.fColor);
joshualitta751c972015-11-20 13:37:32 -080054 }
joshualitta751c972015-11-20 13:37:32 -080055 switch (fMaskType) {
56 case kGrayscaleDistanceField_MaskType:
57 case kGrayscaleCoverageMask_MaskType:
ethannicholasff210322015-11-24 12:10:10 -080058 coverage->setUnknownSingleComponent();
joshualitta751c972015-11-20 13:37:32 -080059 break;
60 case kLCDCoverageMask_MaskType:
61 case kLCDDistanceField_MaskType:
ethannicholasff210322015-11-24 12:10:10 -080062 coverage->setUnknownOpaqueFourComponents();
63 coverage->setUsingLCDCoverage();
joshualitta751c972015-11-20 13:37:32 -080064 break;
65 case kColorBitmapMask_MaskType:
ethannicholasff210322015-11-24 12:10:10 -080066 coverage->setKnownSingleComponent(0xff);
joshualitta751c972015-11-20 13:37:32 -080067 }
68}
69
ethannicholasff210322015-11-24 12:10:10 -080070void GrAtlasTextBatch::initBatchTracker(const GrXPOverridesForBatch& overrides) {
joshualitta751c972015-11-20 13:37:32 -080071 // Handle any color overrides
ethannicholasff210322015-11-24 12:10:10 -080072 if (!overrides.readsColor()) {
joshualitta751c972015-11-20 13:37:32 -080073 fGeoData[0].fColor = GrColor_ILLEGAL;
74 }
ethannicholasff210322015-11-24 12:10:10 -080075 overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
joshualitta751c972015-11-20 13:37:32 -080076
77 // setup batch properties
ethannicholasff210322015-11-24 12:10:10 -080078 fBatch.fColorIgnored = !overrides.readsColor();
joshualitta751c972015-11-20 13:37:32 -080079 fBatch.fColor = fGeoData[0].fColor;
ethannicholasff210322015-11-24 12:10:10 -080080 fBatch.fUsesLocalCoords = overrides.readsLocalCoords();
81 fBatch.fCoverageIgnored = !overrides.readsCoverage();
joshualitta751c972015-11-20 13:37:32 -080082}
83
joshualitt144c3c82015-11-30 12:30:13 -080084void GrAtlasTextBatch::onPrepareDraws(Target* target) const {
joshualitta751c972015-11-20 13:37:32 -080085 // if we have RGB, then we won't have any SkShaders so no need to use a localmatrix.
86 // TODO actually only invert if we don't have RGBA
87 SkMatrix localMatrix;
88 if (this->usesLocalCoords() && !this->viewMatrix().invert(&localMatrix)) {
89 SkDebugf("Cannot invert viewmatrix\n");
90 return;
91 }
92
93 GrTexture* texture = fFontCache->getTexture(this->maskFormat());
94 if (!texture) {
95 SkDebugf("Could not allocate backing texture for atlas\n");
96 return;
97 }
98
joshualitta751c972015-11-20 13:37:32 -080099 GrMaskFormat maskFormat = this->maskFormat();
joshualitta751c972015-11-20 13:37:32 -0800100
bsalomon342bfc22016-04-01 06:06:20 -0700101 FlushInfo flushInfo;
joshualittd9d30f72015-12-08 10:47:55 -0800102 if (this->usesDistanceFields()) {
bungeman06ca8ec2016-06-09 08:01:03 -0700103 flushInfo.fGeometryProcessor =
104 this->setupDfProcessor(this->viewMatrix(), fFilteredColor, this->color(), texture);
joshualitta751c972015-11-20 13:37:32 -0800105 } else {
Brian Salomon514baff2016-11-17 15:17:07 -0500106 GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kNone_FilterMode);
bungeman06ca8ec2016-06-09 08:01:03 -0700107 flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make(this->color(),
108 texture,
109 params,
110 maskFormat,
111 localMatrix,
112 this->usesLocalCoords());
joshualitta751c972015-11-20 13:37:32 -0800113 }
114
joshualitta751c972015-11-20 13:37:32 -0800115 flushInfo.fGlyphsToFlush = 0;
bsalomon342bfc22016-04-01 06:06:20 -0700116 size_t vertexStride = flushInfo.fGeometryProcessor->getVertexStride();
joshualittf528e0d2015-12-09 06:42:52 -0800117 SkASSERT(vertexStride == GrAtlasTextBlob::GetVertexStride(maskFormat));
joshualitta751c972015-11-20 13:37:32 -0800118
joshualitta751c972015-11-20 13:37:32 -0800119 int glyphCount = this->numGlyphs();
cdalton397536c2016-03-25 12:15:03 -0700120 const GrBuffer* vertexBuffer;
joshualitta751c972015-11-20 13:37:32 -0800121
122 void* vertices = target->makeVertexSpace(vertexStride,
123 glyphCount * kVerticesPerGlyph,
124 &vertexBuffer,
125 &flushInfo.fVertexOffset);
126 flushInfo.fVertexBuffer.reset(SkRef(vertexBuffer));
127 flushInfo.fIndexBuffer.reset(target->resourceProvider()->refQuadIndexBuffer());
128 if (!vertices || !flushInfo.fVertexBuffer) {
129 SkDebugf("Could not allocate vertices\n");
130 return;
131 }
132
133 unsigned char* currVertex = reinterpret_cast<unsigned char*>(vertices);
134
bsalomon342bfc22016-04-01 06:06:20 -0700135 GrBlobRegenHelper helper(this, target, &flushInfo);
bsalomond1c71fd2016-05-19 12:51:46 -0700136 SkAutoGlyphCache glyphCache;
joshualitta751c972015-11-20 13:37:32 -0800137 for (int i = 0; i < fGeoCount; i++) {
joshualitt144c3c82015-11-30 12:30:13 -0800138 const Geometry& args = fGeoData[i];
joshualitta751c972015-11-20 13:37:32 -0800139 Blob* blob = args.fBlob;
joshualittddd22d82016-02-16 06:47:52 -0800140 size_t byteCount;
141 void* blobVertices;
joshualitt8e0ef292016-02-19 14:13:03 -0800142 int subRunGlyphCount;
bsalomond1c71fd2016-05-19 12:51:46 -0700143 blob->regenInBatch(target, fFontCache, &helper, args.fRun, args.fSubRun, &glyphCache,
144 vertexStride, args.fViewMatrix, args.fX, args.fY, args.fColor,
145 &blobVertices, &byteCount, &subRunGlyphCount);
joshualitta751c972015-11-20 13:37:32 -0800146
147 // now copy all vertices
joshualittddd22d82016-02-16 06:47:52 -0800148 memcpy(currVertex, blobVertices, byteCount);
joshualitta751c972015-11-20 13:37:32 -0800149
joshualitt7481e752016-01-22 06:08:48 -0800150#ifdef SK_DEBUG
151 // bounds sanity check
152 SkRect rect;
153 rect.setLargestInverted();
joshualittddd22d82016-02-16 06:47:52 -0800154 SkPoint* vertex = (SkPoint*) ((char*)blobVertices);
joshualitt8e0ef292016-02-19 14:13:03 -0800155 rect.growToInclude(vertex, vertexStride, kVerticesPerGlyph * subRunGlyphCount);
joshualitt7481e752016-01-22 06:08:48 -0800156
157 if (this->usesDistanceFields()) {
joshualitt8e0ef292016-02-19 14:13:03 -0800158 args.fViewMatrix.mapRect(&rect);
joshualitt7481e752016-01-22 06:08:48 -0800159 }
bsalomon33b6b8e2016-04-13 08:14:22 -0700160 // Allow for small numerical error in the bounds.
bsalomon88cf17d2016-07-08 06:40:56 -0700161 SkRect bounds = this->bounds();
bsalomon33b6b8e2016-04-13 08:14:22 -0700162 bounds.outset(0.001f, 0.001f);
163 SkASSERT(bounds.contains(rect));
joshualitt7481e752016-01-22 06:08:48 -0800164#endif
165
joshualitta751c972015-11-20 13:37:32 -0800166 currVertex += byteCount;
167 }
joshualitt60ce86d2015-11-23 13:08:22 -0800168
joshualitta751c972015-11-20 13:37:32 -0800169 this->flush(target, &flushInfo);
170}
171
joshualitt144c3c82015-11-30 12:30:13 -0800172void GrAtlasTextBatch::flush(GrVertexBatch::Target* target, FlushInfo* flushInfo) const {
egdaniel0e1853c2016-03-17 11:35:45 -0700173 GrMesh mesh;
cdalton397536c2016-03-25 12:15:03 -0700174 int maxGlyphsPerDraw =
175 static_cast<int>(flushInfo->fIndexBuffer->gpuMemorySize() / sizeof(uint16_t) / 6);
Hal Canary144caf52016-11-07 17:57:18 -0500176 mesh.initInstanced(kTriangles_GrPrimitiveType, flushInfo->fVertexBuffer.get(),
177 flushInfo->fIndexBuffer.get(), flushInfo->fVertexOffset,
egdaniel0e1853c2016-03-17 11:35:45 -0700178 kVerticesPerGlyph, kIndicesPerGlyph, flushInfo->fGlyphsToFlush,
179 maxGlyphsPerDraw);
bungeman06ca8ec2016-06-09 08:01:03 -0700180 target->draw(flushInfo->fGeometryProcessor.get(), mesh);
joshualitta751c972015-11-20 13:37:32 -0800181 flushInfo->fVertexOffset += kVerticesPerGlyph * flushInfo->fGlyphsToFlush;
182 flushInfo->fGlyphsToFlush = 0;
183}
184
185bool GrAtlasTextBatch::onCombineIfPossible(GrBatch* t, const GrCaps& caps) {
186 GrAtlasTextBatch* that = t->cast<GrAtlasTextBatch>();
187 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
188 that->bounds(), caps)) {
189 return false;
190 }
191
192 if (fMaskType != that->fMaskType) {
193 return false;
194 }
195
196 if (!this->usesDistanceFields()) {
joshualittd9d30f72015-12-08 10:47:55 -0800197 if (kColorBitmapMask_MaskType == fMaskType && this->color() != that->color()) {
joshualitta751c972015-11-20 13:37:32 -0800198 return false;
199 }
200 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
201 return false;
202 }
203 } else {
204 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
205 return false;
206 }
207
208 if (fFilteredColor != that->fFilteredColor) {
209 return false;
210 }
211
212 if (fUseBGR != that->fUseBGR) {
213 return false;
214 }
joshualitta751c972015-11-20 13:37:32 -0800215 }
216
217 fBatch.fNumGlyphs += that->numGlyphs();
218
219 // Reallocate space for geo data if necessary and then import that's geo data.
220 int newGeoCount = that->fGeoCount + fGeoCount;
221 // We assume (and here enforce) that the allocation size is the smallest power of two that
222 // is greater than or equal to the number of geometries (and at least
223 // kMinGeometryAllocated).
224 int newAllocSize = GrNextPow2(newGeoCount);
225 int currAllocSize = SkTMax<int>(kMinGeometryAllocated, GrNextPow2(fGeoCount));
226
227 if (newGeoCount > currAllocSize) {
228 fGeoData.realloc(newAllocSize);
229 }
230
231 memcpy(&fGeoData[fGeoCount], that->fGeoData.get(), that->fGeoCount * sizeof(Geometry));
232 // We steal the ref on the blobs from the other TextBatch and set its count to 0 so that
233 // it doesn't try to unref them.
234#ifdef SK_DEBUG
235 for (int i = 0; i < that->fGeoCount; ++i) {
236 that->fGeoData.get()[i].fBlob = (Blob*)0x1;
237 }
238#endif
239 that->fGeoCount = 0;
240 fGeoCount = newGeoCount;
241
bsalomon88cf17d2016-07-08 06:40:56 -0700242 this->joinBounds(*that);
joshualitta751c972015-11-20 13:37:32 -0800243 return true;
244}
245
246// TODO just use class params
247// TODO trying to figure out why lcd is so whack
bungeman06ca8ec2016-06-09 08:01:03 -0700248sk_sp<GrGeometryProcessor> GrAtlasTextBatch::setupDfProcessor(const SkMatrix& viewMatrix,
249 SkColor filteredColor,
250 GrColor color,
251 GrTexture* texture) const {
Brian Salomon514baff2016-11-17 15:17:07 -0500252 GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kBilerp_FilterMode);
joshualitta751c972015-11-20 13:37:32 -0800253 bool isLCD = this->isLCD();
254 // set up any flags
255 uint32_t flags = viewMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
jvanverthcf371bb2016-03-10 11:10:43 -0800256 flags |= viewMatrix.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0;
brianosmanb461d342016-04-13 13:10:14 -0700257 flags |= fUseGammaCorrectDistanceTable ? kGammaCorrect_DistanceFieldEffectFlag : 0;
joshualitta751c972015-11-20 13:37:32 -0800258
259 // see if we need to create a new effect
260 if (isLCD) {
261 flags |= kUseLCD_DistanceFieldEffectFlag;
joshualitta751c972015-11-20 13:37:32 -0800262 flags |= fUseBGR ? kBGR_DistanceFieldEffectFlag : 0;
joshualitta751c972015-11-20 13:37:32 -0800263
264 GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor);
265
brianosman0586f5c2016-04-12 12:48:21 -0700266 float redCorrection = fDistanceAdjustTable->getAdjustment(
brianosmanb461d342016-04-13 13:10:14 -0700267 GrColorUnpackR(colorNoPreMul) >> kDistanceAdjustLumShift,
268 fUseGammaCorrectDistanceTable);
brianosman0586f5c2016-04-12 12:48:21 -0700269 float greenCorrection = fDistanceAdjustTable->getAdjustment(
brianosmanb461d342016-04-13 13:10:14 -0700270 GrColorUnpackG(colorNoPreMul) >> kDistanceAdjustLumShift,
271 fUseGammaCorrectDistanceTable);
brianosman0586f5c2016-04-12 12:48:21 -0700272 float blueCorrection = fDistanceAdjustTable->getAdjustment(
brianosmanb461d342016-04-13 13:10:14 -0700273 GrColorUnpackB(colorNoPreMul) >> kDistanceAdjustLumShift,
274 fUseGammaCorrectDistanceTable);
joshualitta751c972015-11-20 13:37:32 -0800275 GrDistanceFieldLCDTextGeoProc::DistanceAdjust widthAdjust =
276 GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(redCorrection,
277 greenCorrection,
278 blueCorrection);
279
bungeman06ca8ec2016-06-09 08:01:03 -0700280 return GrDistanceFieldLCDTextGeoProc::Make(color,
281 viewMatrix,
282 texture,
283 params,
284 widthAdjust,
285 flags,
286 this->usesLocalCoords());
joshualitta751c972015-11-20 13:37:32 -0800287 } else {
joshualitta751c972015-11-20 13:37:32 -0800288#ifdef SK_GAMMA_APPLY_TO_A8
289 U8CPU lum = SkColorSpaceLuminance::computeLuminance(SK_GAMMA_EXPONENT, filteredColor);
brianosman0586f5c2016-04-12 12:48:21 -0700290 float correction = fDistanceAdjustTable->getAdjustment(
brianosmanb461d342016-04-13 13:10:14 -0700291 lum >> kDistanceAdjustLumShift, fUseGammaCorrectDistanceTable);
bungeman06ca8ec2016-06-09 08:01:03 -0700292 return GrDistanceFieldA8TextGeoProc::Make(color,
293 viewMatrix,
294 texture,
295 params,
296 correction,
297 flags,
298 this->usesLocalCoords());
joshualitta751c972015-11-20 13:37:32 -0800299#else
bungeman06ca8ec2016-06-09 08:01:03 -0700300 return GrDistanceFieldA8TextGeoProc::Make(color,
301 viewMatrix,
302 texture,
303 params,
304 flags,
305 this->usesLocalCoords());
joshualitta751c972015-11-20 13:37:32 -0800306#endif
307 }
308
309}
joshualittddd22d82016-02-16 06:47:52 -0800310
311void GrBlobRegenHelper::flush() {
312 fBatch->flush(fTarget, fFlushInfo);
joshualittddd22d82016-02-16 06:47:52 -0800313}