Line data Source code
1 : /*
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 "GrAtlasTextOp.h"
9 :
10 : #include "GrContext.h"
11 : #include "GrOpFlushState.h"
12 : #include "GrResourceProvider.h"
13 :
14 : #include "SkGlyphCache.h"
15 : #include "SkMathPriv.h"
16 :
17 : #include "effects/GrBitmapTextGeoProc.h"
18 : #include "effects/GrDistanceFieldGeoProc.h"
19 : #include "text/GrAtlasGlyphCache.h"
20 :
21 : ///////////////////////////////////////////////////////////////////////////////////////////////////
22 :
23 0 : static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
24 0 : unsigned r = SkColorGetR(c);
25 0 : unsigned g = SkColorGetG(c);
26 0 : unsigned b = SkColorGetB(c);
27 0 : return GrColorPackRGBA(r, g, b, 0xff);
28 : }
29 :
30 : static const int kDistanceAdjustLumShift = 5;
31 :
32 0 : SkString GrAtlasTextOp::dumpInfo() const {
33 0 : SkString str;
34 :
35 0 : for (int i = 0; i < fGeoCount; ++i) {
36 0 : str.appendf("%d: Color: 0x%08x Trans: %.2f,%.2f Runs: %d\n",
37 : i,
38 0 : fGeoData[i].fColor,
39 0 : fGeoData[i].fX,
40 0 : fGeoData[i].fY,
41 0 : fGeoData[i].fBlob->runCount());
42 : }
43 :
44 0 : str.append(DumpPipelineInfo(*this->pipeline()));
45 0 : str.append(INHERITED::dumpInfo());
46 0 : return str;
47 : }
48 :
49 0 : void GrAtlasTextOp::getProcessorAnalysisInputs(GrProcessorAnalysisColor* color,
50 : GrProcessorAnalysisCoverage* coverage) const {
51 0 : if (kColorBitmapMask_MaskType == fMaskType) {
52 0 : color->setToUnknown();
53 : } else {
54 0 : color->setToConstant(fColor);
55 : }
56 0 : switch (fMaskType) {
57 : case kGrayscaleDistanceField_MaskType:
58 : case kGrayscaleCoverageMask_MaskType:
59 0 : *coverage = GrProcessorAnalysisCoverage::kSingleChannel;
60 0 : break;
61 : case kLCDCoverageMask_MaskType:
62 : case kLCDDistanceField_MaskType:
63 0 : *coverage = GrProcessorAnalysisCoverage::kLCD;
64 0 : break;
65 : case kColorBitmapMask_MaskType:
66 0 : *coverage = GrProcessorAnalysisCoverage::kNone;
67 0 : break;
68 : }
69 0 : }
70 :
71 0 : void GrAtlasTextOp::applyPipelineOptimizations(const PipelineOptimizations& optimizations) {
72 0 : optimizations.getOverrideColorIfSet(&fGeoData[0].fColor);
73 :
74 0 : fColor = fGeoData[0].fColor;
75 0 : fUsesLocalCoords = optimizations.readsLocalCoords();
76 0 : }
77 :
78 0 : void GrAtlasTextOp::onPrepareDraws(Target* target) const {
79 : // 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 0 : if (this->usesLocalCoords() && !this->viewMatrix().invert(&localMatrix)) {
83 0 : SkDebugf("Cannot invert viewmatrix\n");
84 0 : return;
85 : }
86 :
87 0 : sk_sp<GrTextureProxy> proxy = fFontCache->getProxy(this->maskFormat());
88 0 : if (!proxy) {
89 0 : SkDebugf("Could not allocate backing texture for atlas\n");
90 0 : return;
91 : }
92 :
93 0 : GrMaskFormat maskFormat = this->maskFormat();
94 :
95 0 : FlushInfo flushInfo;
96 0 : if (this->usesDistanceFields()) {
97 : flushInfo.fGeometryProcessor =
98 0 : this->setupDfProcessor(fFontCache->context()->resourceProvider(),
99 : this->viewMatrix(),
100 0 : fFilteredColor, this->color(), std::move(proxy));
101 : } else {
102 0 : GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kNone_FilterMode);
103 0 : flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make(
104 0 : fFontCache->context()->resourceProvider(),
105 0 : this->color(), std::move(proxy), params,
106 0 : maskFormat, localMatrix, this->usesLocalCoords());
107 : }
108 :
109 0 : flushInfo.fGlyphsToFlush = 0;
110 0 : size_t vertexStride = flushInfo.fGeometryProcessor->getVertexStride();
111 0 : SkASSERT(vertexStride == GrAtlasTextBlob::GetVertexStride(maskFormat));
112 :
113 0 : int glyphCount = this->numGlyphs();
114 : const GrBuffer* vertexBuffer;
115 :
116 0 : void* vertices = target->makeVertexSpace(
117 0 : vertexStride, glyphCount * kVerticesPerGlyph, &vertexBuffer, &flushInfo.fVertexOffset);
118 0 : flushInfo.fVertexBuffer.reset(SkRef(vertexBuffer));
119 0 : flushInfo.fIndexBuffer.reset(target->resourceProvider()->refQuadIndexBuffer());
120 0 : if (!vertices || !flushInfo.fVertexBuffer) {
121 0 : SkDebugf("Could not allocate vertices\n");
122 0 : return;
123 : }
124 :
125 0 : unsigned char* currVertex = reinterpret_cast<unsigned char*>(vertices);
126 :
127 0 : GrBlobRegenHelper helper(this, target, &flushInfo);
128 0 : SkAutoGlyphCache glyphCache;
129 0 : for (int i = 0; i < fGeoCount; i++) {
130 0 : const Geometry& args = fGeoData[i];
131 0 : Blob* blob = args.fBlob;
132 : size_t byteCount;
133 : void* blobVertices;
134 : int subRunGlyphCount;
135 0 : blob->regenInOp(target, fFontCache, &helper, args.fRun, args.fSubRun, &glyphCache,
136 0 : vertexStride, args.fViewMatrix, args.fX, args.fY, args.fColor,
137 0 : &blobVertices, &byteCount, &subRunGlyphCount);
138 :
139 : // now copy all vertices
140 0 : memcpy(currVertex, blobVertices, byteCount);
141 :
142 0 : currVertex += byteCount;
143 : }
144 :
145 0 : this->flush(target, &flushInfo);
146 : }
147 :
148 0 : void GrAtlasTextOp::flush(GrLegacyMeshDrawOp::Target* target, FlushInfo* flushInfo) const {
149 0 : GrMesh mesh;
150 : int maxGlyphsPerDraw =
151 0 : static_cast<int>(flushInfo->fIndexBuffer->gpuMemorySize() / sizeof(uint16_t) / 6);
152 0 : mesh.initInstanced(kTriangles_GrPrimitiveType, flushInfo->fVertexBuffer.get(),
153 : flushInfo->fIndexBuffer.get(), flushInfo->fVertexOffset, kVerticesPerGlyph,
154 0 : kIndicesPerGlyph, flushInfo->fGlyphsToFlush, maxGlyphsPerDraw);
155 0 : target->draw(flushInfo->fGeometryProcessor.get(), this->pipeline(), mesh);
156 0 : flushInfo->fVertexOffset += kVerticesPerGlyph * flushInfo->fGlyphsToFlush;
157 0 : flushInfo->fGlyphsToFlush = 0;
158 0 : }
159 :
160 0 : bool GrAtlasTextOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
161 0 : GrAtlasTextOp* that = t->cast<GrAtlasTextOp>();
162 0 : if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
163 : that->bounds(), caps)) {
164 0 : return false;
165 : }
166 :
167 0 : if (fMaskType != that->fMaskType) {
168 0 : return false;
169 : }
170 :
171 0 : if (!this->usesDistanceFields()) {
172 0 : if (kColorBitmapMask_MaskType == fMaskType && this->color() != that->color()) {
173 0 : return false;
174 : }
175 0 : if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
176 0 : return false;
177 : }
178 : } else {
179 0 : if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
180 0 : return false;
181 : }
182 :
183 0 : if (fFilteredColor != that->fFilteredColor) {
184 0 : return false;
185 : }
186 :
187 0 : if (fUseBGR != that->fUseBGR) {
188 0 : return false;
189 : }
190 : }
191 :
192 0 : fNumGlyphs += that->numGlyphs();
193 :
194 : // Reallocate space for geo data if necessary and then import that's geo data.
195 0 : int newGeoCount = that->fGeoCount + fGeoCount;
196 : // We assume (and here enforce) that the allocation size is the smallest power of two that
197 : // is greater than or equal to the number of geometries (and at least
198 : // kMinGeometryAllocated).
199 0 : int newAllocSize = GrNextPow2(newGeoCount);
200 0 : int currAllocSize = SkTMax<int>(kMinGeometryAllocated, GrNextPow2(fGeoCount));
201 :
202 0 : if (newGeoCount > currAllocSize) {
203 0 : fGeoData.realloc(newAllocSize);
204 : }
205 :
206 : // We steal the ref on the blobs from the other AtlasTextOp and set its count to 0 so that
207 : // it doesn't try to unref them.
208 0 : memcpy(&fGeoData[fGeoCount], that->fGeoData.get(), that->fGeoCount * sizeof(Geometry));
209 : #ifdef SK_DEBUG
210 0 : for (int i = 0; i < that->fGeoCount; ++i) {
211 0 : that->fGeoData.get()[i].fBlob = (Blob*)0x1;
212 : }
213 : #endif
214 0 : that->fGeoCount = 0;
215 0 : fGeoCount = newGeoCount;
216 :
217 0 : this->joinBounds(*that);
218 0 : return true;
219 : }
220 :
221 : // TODO just use class params
222 : // TODO trying to figure out why lcd is so whack
223 0 : sk_sp<GrGeometryProcessor> GrAtlasTextOp::setupDfProcessor(GrResourceProvider* resourceProvider,
224 : const SkMatrix& viewMatrix,
225 : SkColor filteredColor,
226 : GrColor color,
227 : sk_sp<GrTextureProxy> proxy) const {
228 0 : GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kBilerp_FilterMode);
229 0 : bool isLCD = this->isLCD();
230 : // set up any flags
231 0 : uint32_t flags = viewMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
232 0 : flags |= viewMatrix.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0;
233 0 : flags |= fUseGammaCorrectDistanceTable ? kGammaCorrect_DistanceFieldEffectFlag : 0;
234 :
235 : // see if we need to create a new effect
236 0 : if (isLCD) {
237 0 : flags |= kUseLCD_DistanceFieldEffectFlag;
238 0 : flags |= fUseBGR ? kBGR_DistanceFieldEffectFlag : 0;
239 :
240 0 : GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor);
241 :
242 : float redCorrection = fDistanceAdjustTable->getAdjustment(
243 0 : GrColorUnpackR(colorNoPreMul) >> kDistanceAdjustLumShift,
244 0 : fUseGammaCorrectDistanceTable);
245 : float greenCorrection = fDistanceAdjustTable->getAdjustment(
246 0 : GrColorUnpackG(colorNoPreMul) >> kDistanceAdjustLumShift,
247 0 : fUseGammaCorrectDistanceTable);
248 : float blueCorrection = fDistanceAdjustTable->getAdjustment(
249 0 : GrColorUnpackB(colorNoPreMul) >> kDistanceAdjustLumShift,
250 0 : fUseGammaCorrectDistanceTable);
251 : GrDistanceFieldLCDTextGeoProc::DistanceAdjust widthAdjust =
252 : GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(
253 0 : redCorrection, greenCorrection, blueCorrection);
254 :
255 : return GrDistanceFieldLCDTextGeoProc::Make(resourceProvider,
256 0 : color, viewMatrix, std::move(proxy),
257 : params, widthAdjust, flags,
258 0 : this->usesLocalCoords());
259 : } else {
260 : #ifdef SK_GAMMA_APPLY_TO_A8
261 : U8CPU lum = SkColorSpaceLuminance::computeLuminance(SK_GAMMA_EXPONENT, filteredColor);
262 : float correction = fDistanceAdjustTable->getAdjustment(lum >> kDistanceAdjustLumShift,
263 : fUseGammaCorrectDistanceTable);
264 : return GrDistanceFieldA8TextGeoProc::Make(resourceProvider, color,
265 : viewMatrix, std::move(proxy),
266 : params, correction, flags,
267 : this->usesLocalCoords());
268 : #else
269 : return GrDistanceFieldA8TextGeoProc::Make(resourceProvider, color,
270 0 : viewMatrix, std::move(proxy),
271 0 : params, flags, this->usesLocalCoords());
272 : #endif
273 : }
274 : }
275 :
276 0 : void GrBlobRegenHelper::flush() { fOp->flush(fTarget, fFlushInfo); }
|