xref: /aosp_15_r20/external/skia/src/gpu/ganesh/ops/AtlasTextOp.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2015 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/AtlasTextOp.h"
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSamplingOptions.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTArray.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkArenaAlloc.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkMatrixPriv.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkTraceEvent.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrBufferAllocPool.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrCaps.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrColorSpaceXform.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrGeometryProcessor.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrMeshDrawTarget.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrOpFlushState.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrPaint.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrPipeline.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProcessorAnalysis.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrResourceProvider.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrSamplerState.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrSimpleMesh.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrSurfaceProxy.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrSurfaceProxyView.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrUserStencilSettings.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/effects/GrBitmapTextGeoProc.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/effects/GrDistanceFieldGeoProc.h"
34*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/GrDrawOp.h"
35*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/GrSimpleMeshDrawOpHelper.h"
36*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/text/GrAtlasManager.h"
37*c8dee2aaSAndroid Build Coastguard Worker #include "src/text/gpu/DistanceFieldAdjustTable.h"
38*c8dee2aaSAndroid Build Coastguard Worker #include "src/text/gpu/GlyphVector.h"
39*c8dee2aaSAndroid Build Coastguard Worker #include "src/text/gpu/SubRunContainer.h"
40*c8dee2aaSAndroid Build Coastguard Worker 
41*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_GAMMA_APPLY_TO_A8)
42*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkCPUTypes.h"
43*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkMaskGamma.h"
44*c8dee2aaSAndroid Build Coastguard Worker #endif
45*c8dee2aaSAndroid Build Coastguard Worker 
46*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
47*c8dee2aaSAndroid Build Coastguard Worker #include <functional>
48*c8dee2aaSAndroid Build Coastguard Worker #include <new>
49*c8dee2aaSAndroid Build Coastguard Worker #include <tuple>
50*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
51*c8dee2aaSAndroid Build Coastguard Worker 
52*c8dee2aaSAndroid Build Coastguard Worker struct GrShaderCaps;
53*c8dee2aaSAndroid Build Coastguard Worker 
54*c8dee2aaSAndroid Build Coastguard Worker using MaskFormat = skgpu::MaskFormat;
55*c8dee2aaSAndroid Build Coastguard Worker 
56*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::ganesh {
57*c8dee2aaSAndroid Build Coastguard Worker 
58*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr int kVerticesPerGlyph = 4;
59*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr int kIndicesPerGlyph = 6;
60*c8dee2aaSAndroid Build Coastguard Worker 
61*c8dee2aaSAndroid Build Coastguard Worker // If we have thread local, then cache memory for a single AtlasTextOp.
62*c8dee2aaSAndroid Build Coastguard Worker static thread_local void* gCache = nullptr;
operator new(size_t s)63*c8dee2aaSAndroid Build Coastguard Worker void* AtlasTextOp::operator new(size_t s) {
64*c8dee2aaSAndroid Build Coastguard Worker     if (gCache != nullptr) {
65*c8dee2aaSAndroid Build Coastguard Worker         return std::exchange(gCache, nullptr);
66*c8dee2aaSAndroid Build Coastguard Worker     }
67*c8dee2aaSAndroid Build Coastguard Worker 
68*c8dee2aaSAndroid Build Coastguard Worker     return ::operator new(s);
69*c8dee2aaSAndroid Build Coastguard Worker }
70*c8dee2aaSAndroid Build Coastguard Worker 
operator delete(void * bytes)71*c8dee2aaSAndroid Build Coastguard Worker void AtlasTextOp::operator delete(void* bytes) noexcept {
72*c8dee2aaSAndroid Build Coastguard Worker     if (gCache == nullptr) {
73*c8dee2aaSAndroid Build Coastguard Worker         gCache = bytes;
74*c8dee2aaSAndroid Build Coastguard Worker         return;
75*c8dee2aaSAndroid Build Coastguard Worker     }
76*c8dee2aaSAndroid Build Coastguard Worker     ::operator delete(bytes);
77*c8dee2aaSAndroid Build Coastguard Worker }
78*c8dee2aaSAndroid Build Coastguard Worker 
ClearCache()79*c8dee2aaSAndroid Build Coastguard Worker void AtlasTextOp::ClearCache() {
80*c8dee2aaSAndroid Build Coastguard Worker     ::operator delete(gCache);
81*c8dee2aaSAndroid Build Coastguard Worker     gCache = nullptr;
82*c8dee2aaSAndroid Build Coastguard Worker }
83*c8dee2aaSAndroid Build Coastguard Worker 
AtlasTextOp(MaskType maskType,bool needsTransform,int glyphCount,SkRect deviceRect,Geometry * geo,const GrColorInfo & dstColorInfo,GrPaint && paint)84*c8dee2aaSAndroid Build Coastguard Worker AtlasTextOp::AtlasTextOp(MaskType maskType,
85*c8dee2aaSAndroid Build Coastguard Worker                          bool needsTransform,
86*c8dee2aaSAndroid Build Coastguard Worker                          int glyphCount,
87*c8dee2aaSAndroid Build Coastguard Worker                          SkRect deviceRect,
88*c8dee2aaSAndroid Build Coastguard Worker                          Geometry* geo,
89*c8dee2aaSAndroid Build Coastguard Worker                          const GrColorInfo& dstColorInfo,
90*c8dee2aaSAndroid Build Coastguard Worker                          GrPaint&& paint)
91*c8dee2aaSAndroid Build Coastguard Worker         : INHERITED{ClassID()}
92*c8dee2aaSAndroid Build Coastguard Worker         , fProcessors(std::move(paint))
93*c8dee2aaSAndroid Build Coastguard Worker         , fNumGlyphs(glyphCount)
94*c8dee2aaSAndroid Build Coastguard Worker         , fDFGPFlags(0)
95*c8dee2aaSAndroid Build Coastguard Worker         , fMaskType(static_cast<uint32_t>(maskType))
96*c8dee2aaSAndroid Build Coastguard Worker         , fUsesLocalCoords(false)
97*c8dee2aaSAndroid Build Coastguard Worker         , fNeedsGlyphTransform(needsTransform)
98*c8dee2aaSAndroid Build Coastguard Worker         , fHasPerspective(needsTransform && geo->fDrawMatrix.hasPerspective())
99*c8dee2aaSAndroid Build Coastguard Worker         , fUseGammaCorrectDistanceTable(false)
100*c8dee2aaSAndroid Build Coastguard Worker         , fHead{geo}
101*c8dee2aaSAndroid Build Coastguard Worker         , fTail{&fHead->fNext} {
102*c8dee2aaSAndroid Build Coastguard Worker     // We don't have tight bounds on the glyph paths in device space. For the purposes of bounds
103*c8dee2aaSAndroid Build Coastguard Worker     // we treat this as a set of non-AA rects rendered with a texture.
104*c8dee2aaSAndroid Build Coastguard Worker     this->setBounds(deviceRect, HasAABloat::kNo, IsHairline::kNo);
105*c8dee2aaSAndroid Build Coastguard Worker     if (maskType == MaskType::kColorBitmap) {
106*c8dee2aaSAndroid Build Coastguard Worker         // We assume that color emoji use the sRGB colorspace
107*c8dee2aaSAndroid Build Coastguard Worker         fColorSpaceXform = dstColorInfo.refColorSpaceXformFromSRGB();
108*c8dee2aaSAndroid Build Coastguard Worker     }
109*c8dee2aaSAndroid Build Coastguard Worker }
110*c8dee2aaSAndroid Build Coastguard Worker 
AtlasTextOp(MaskType maskType,bool needsTransform,int glyphCount,SkRect deviceRect,SkColor luminanceColor,bool useGammaCorrectDistanceTable,uint32_t DFGPFlags,Geometry * geo,GrPaint && paint)111*c8dee2aaSAndroid Build Coastguard Worker AtlasTextOp::AtlasTextOp(MaskType maskType,
112*c8dee2aaSAndroid Build Coastguard Worker                          bool needsTransform,
113*c8dee2aaSAndroid Build Coastguard Worker                          int glyphCount,
114*c8dee2aaSAndroid Build Coastguard Worker                          SkRect deviceRect,
115*c8dee2aaSAndroid Build Coastguard Worker                          SkColor luminanceColor,
116*c8dee2aaSAndroid Build Coastguard Worker                          bool useGammaCorrectDistanceTable,
117*c8dee2aaSAndroid Build Coastguard Worker                          uint32_t DFGPFlags,
118*c8dee2aaSAndroid Build Coastguard Worker                          Geometry* geo,
119*c8dee2aaSAndroid Build Coastguard Worker                          GrPaint&& paint)
120*c8dee2aaSAndroid Build Coastguard Worker         : INHERITED{ClassID()}
121*c8dee2aaSAndroid Build Coastguard Worker         , fProcessors(std::move(paint))
122*c8dee2aaSAndroid Build Coastguard Worker         , fNumGlyphs(glyphCount)
123*c8dee2aaSAndroid Build Coastguard Worker         , fDFGPFlags(DFGPFlags)
124*c8dee2aaSAndroid Build Coastguard Worker         , fMaskType(static_cast<uint32_t>(maskType))
125*c8dee2aaSAndroid Build Coastguard Worker         , fUsesLocalCoords(false)
126*c8dee2aaSAndroid Build Coastguard Worker         , fNeedsGlyphTransform(needsTransform)
127*c8dee2aaSAndroid Build Coastguard Worker         , fHasPerspective(needsTransform && geo->fDrawMatrix.hasPerspective())
128*c8dee2aaSAndroid Build Coastguard Worker         , fUseGammaCorrectDistanceTable(useGammaCorrectDistanceTable)
129*c8dee2aaSAndroid Build Coastguard Worker         , fLuminanceColor(luminanceColor)
130*c8dee2aaSAndroid Build Coastguard Worker         , fHead{geo}
131*c8dee2aaSAndroid Build Coastguard Worker         , fTail{&fHead->fNext} {
132*c8dee2aaSAndroid Build Coastguard Worker     // We don't have tight bounds on the glyph paths in device space. For the purposes of bounds
133*c8dee2aaSAndroid Build Coastguard Worker     // we treat this as a set of non-AA rects rendered with a texture.
134*c8dee2aaSAndroid Build Coastguard Worker     this->setBounds(deviceRect, HasAABloat::kNo, IsHairline::kNo);
135*c8dee2aaSAndroid Build Coastguard Worker }
136*c8dee2aaSAndroid Build Coastguard Worker 
Make(const sktext::gpu::AtlasSubRun & subRun,const SkMatrix & drawMatrix,SkPoint drawOrigin,SkIRect clipRect,sk_sp<SkRefCnt> && supportData,const SkPMColor4f & color,SkArenaAlloc * alloc)137*c8dee2aaSAndroid Build Coastguard Worker auto AtlasTextOp::Geometry::Make(const sktext::gpu::AtlasSubRun& subRun,
138*c8dee2aaSAndroid Build Coastguard Worker                                  const SkMatrix& drawMatrix,
139*c8dee2aaSAndroid Build Coastguard Worker                                  SkPoint drawOrigin,
140*c8dee2aaSAndroid Build Coastguard Worker                                  SkIRect clipRect,
141*c8dee2aaSAndroid Build Coastguard Worker                                  sk_sp<SkRefCnt>&& supportData,
142*c8dee2aaSAndroid Build Coastguard Worker                                  const SkPMColor4f& color,
143*c8dee2aaSAndroid Build Coastguard Worker                                  SkArenaAlloc* alloc) -> Geometry* {
144*c8dee2aaSAndroid Build Coastguard Worker     // Bypass the automatic dtor behavior in SkArenaAlloc. I'm leaving this up to the Op to run
145*c8dee2aaSAndroid Build Coastguard Worker     // all geometry dtors for now.
146*c8dee2aaSAndroid Build Coastguard Worker     void* geo = alloc->makeBytesAlignedTo(sizeof(Geometry), alignof(Geometry));
147*c8dee2aaSAndroid Build Coastguard Worker     return new(geo) Geometry{subRun,
148*c8dee2aaSAndroid Build Coastguard Worker                              drawMatrix,
149*c8dee2aaSAndroid Build Coastguard Worker                              drawOrigin,
150*c8dee2aaSAndroid Build Coastguard Worker                              clipRect,
151*c8dee2aaSAndroid Build Coastguard Worker                              std::move(supportData),
152*c8dee2aaSAndroid Build Coastguard Worker                              color};
153*c8dee2aaSAndroid Build Coastguard Worker }
154*c8dee2aaSAndroid Build Coastguard Worker 
fillVertexData(void * dst,int offset,int count) const155*c8dee2aaSAndroid Build Coastguard Worker void AtlasTextOp::Geometry::fillVertexData(void *dst, int offset, int count) const {
156*c8dee2aaSAndroid Build Coastguard Worker     fSubRun.fillVertexData(
157*c8dee2aaSAndroid Build Coastguard Worker             dst, offset, count, fColor.toBytes_RGBA(), fDrawMatrix, fDrawOrigin, fClipRect);
158*c8dee2aaSAndroid Build Coastguard Worker }
159*c8dee2aaSAndroid Build Coastguard Worker 
visitProxies(const GrVisitProxyFunc & func) const160*c8dee2aaSAndroid Build Coastguard Worker void AtlasTextOp::visitProxies(const GrVisitProxyFunc& func) const {
161*c8dee2aaSAndroid Build Coastguard Worker     fProcessors.visitProxies(func);
162*c8dee2aaSAndroid Build Coastguard Worker }
163*c8dee2aaSAndroid Build Coastguard Worker 
164*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
onDumpInfo() const165*c8dee2aaSAndroid Build Coastguard Worker SkString AtlasTextOp::onDumpInfo() const {
166*c8dee2aaSAndroid Build Coastguard Worker     SkString str;
167*c8dee2aaSAndroid Build Coastguard Worker     int i = 0;
168*c8dee2aaSAndroid Build Coastguard Worker     for(Geometry* geom = fHead; geom != nullptr; geom = geom->fNext) {
169*c8dee2aaSAndroid Build Coastguard Worker         str.appendf("%d: Color: 0x%08x Trans: %.2f,%.2f\n",
170*c8dee2aaSAndroid Build Coastguard Worker                     i++,
171*c8dee2aaSAndroid Build Coastguard Worker                     geom->fColor.toBytes_RGBA(),
172*c8dee2aaSAndroid Build Coastguard Worker                     geom->fDrawOrigin.x(),
173*c8dee2aaSAndroid Build Coastguard Worker                     geom->fDrawOrigin.y());
174*c8dee2aaSAndroid Build Coastguard Worker     }
175*c8dee2aaSAndroid Build Coastguard Worker 
176*c8dee2aaSAndroid Build Coastguard Worker     str += fProcessors.dumpProcessors();
177*c8dee2aaSAndroid Build Coastguard Worker     return str;
178*c8dee2aaSAndroid Build Coastguard Worker }
179*c8dee2aaSAndroid Build Coastguard Worker #endif
180*c8dee2aaSAndroid Build Coastguard Worker 
fixedFunctionFlags() const181*c8dee2aaSAndroid Build Coastguard Worker GrDrawOp::FixedFunctionFlags AtlasTextOp::fixedFunctionFlags() const {
182*c8dee2aaSAndroid Build Coastguard Worker     return FixedFunctionFlags::kNone;
183*c8dee2aaSAndroid Build Coastguard Worker }
184*c8dee2aaSAndroid Build Coastguard Worker 
finalize(const GrCaps & caps,const GrAppliedClip * clip,GrClampType clampType)185*c8dee2aaSAndroid Build Coastguard Worker GrProcessorSet::Analysis AtlasTextOp::finalize(const GrCaps& caps,
186*c8dee2aaSAndroid Build Coastguard Worker                                                const GrAppliedClip* clip,
187*c8dee2aaSAndroid Build Coastguard Worker                                                GrClampType clampType) {
188*c8dee2aaSAndroid Build Coastguard Worker     GrProcessorAnalysisCoverage coverage;
189*c8dee2aaSAndroid Build Coastguard Worker     GrProcessorAnalysisColor color;
190*c8dee2aaSAndroid Build Coastguard Worker     if (this->maskType() == MaskType::kColorBitmap) {
191*c8dee2aaSAndroid Build Coastguard Worker         color.setToUnknown();
192*c8dee2aaSAndroid Build Coastguard Worker     } else {
193*c8dee2aaSAndroid Build Coastguard Worker         // finalize() is called before any merging is done, so at this point there's at most one
194*c8dee2aaSAndroid Build Coastguard Worker         // Geometry with a color. Later, for non-bitmap ops, we may have mixed colors.
195*c8dee2aaSAndroid Build Coastguard Worker         color.setToConstant(fHead->fColor);
196*c8dee2aaSAndroid Build Coastguard Worker     }
197*c8dee2aaSAndroid Build Coastguard Worker 
198*c8dee2aaSAndroid Build Coastguard Worker     switch (this->maskType()) {
199*c8dee2aaSAndroid Build Coastguard Worker         case MaskType::kGrayscaleCoverage:
200*c8dee2aaSAndroid Build Coastguard Worker #if !defined(SK_DISABLE_SDF_TEXT)
201*c8dee2aaSAndroid Build Coastguard Worker         case MaskType::kAliasedDistanceField:
202*c8dee2aaSAndroid Build Coastguard Worker         case MaskType::kGrayscaleDistanceField:
203*c8dee2aaSAndroid Build Coastguard Worker #endif
204*c8dee2aaSAndroid Build Coastguard Worker             coverage = GrProcessorAnalysisCoverage::kSingleChannel;
205*c8dee2aaSAndroid Build Coastguard Worker             break;
206*c8dee2aaSAndroid Build Coastguard Worker         case MaskType::kLCDCoverage:
207*c8dee2aaSAndroid Build Coastguard Worker #if !defined(SK_DISABLE_SDF_TEXT)
208*c8dee2aaSAndroid Build Coastguard Worker         case MaskType::kLCDDistanceField:
209*c8dee2aaSAndroid Build Coastguard Worker #endif
210*c8dee2aaSAndroid Build Coastguard Worker             coverage = GrProcessorAnalysisCoverage::kLCD;
211*c8dee2aaSAndroid Build Coastguard Worker             break;
212*c8dee2aaSAndroid Build Coastguard Worker         case MaskType::kColorBitmap:
213*c8dee2aaSAndroid Build Coastguard Worker             coverage = GrProcessorAnalysisCoverage::kNone;
214*c8dee2aaSAndroid Build Coastguard Worker             break;
215*c8dee2aaSAndroid Build Coastguard Worker     }
216*c8dee2aaSAndroid Build Coastguard Worker 
217*c8dee2aaSAndroid Build Coastguard Worker     auto analysis = fProcessors.finalize(color, coverage, clip, &GrUserStencilSettings::kUnused,
218*c8dee2aaSAndroid Build Coastguard Worker                                          caps, clampType, &fHead->fColor);
219*c8dee2aaSAndroid Build Coastguard Worker     // TODO(michaelludwig): Once processor analysis can be done external to op creation/finalization
220*c8dee2aaSAndroid Build Coastguard Worker     // the atlas op metadata can be fully const. This is okay for now since finalize() happens
221*c8dee2aaSAndroid Build Coastguard Worker     // before the op is merged, so during combineIfPossible, metadata is effectively const.
222*c8dee2aaSAndroid Build Coastguard Worker     fUsesLocalCoords = analysis.usesLocalCoords();
223*c8dee2aaSAndroid Build Coastguard Worker     return analysis;
224*c8dee2aaSAndroid Build Coastguard Worker }
225*c8dee2aaSAndroid Build Coastguard Worker 
onPrepareDraws(GrMeshDrawTarget * target)226*c8dee2aaSAndroid Build Coastguard Worker void AtlasTextOp::onPrepareDraws(GrMeshDrawTarget* target) {
227*c8dee2aaSAndroid Build Coastguard Worker     auto resourceProvider = target->resourceProvider();
228*c8dee2aaSAndroid Build Coastguard Worker 
229*c8dee2aaSAndroid Build Coastguard Worker     // If we need local coordinates, compute an inverse view matrix. If this is solid color, the
230*c8dee2aaSAndroid Build Coastguard Worker     // processor analysis will not require local coords and the GPs will skip local coords when
231*c8dee2aaSAndroid Build Coastguard Worker     // the matrix is identity. When the shaders require local coords, combineIfPossible requires all
232*c8dee2aaSAndroid Build Coastguard Worker     // all geometries to have same draw matrix.
233*c8dee2aaSAndroid Build Coastguard Worker     SkMatrix localMatrix = SkMatrix::I();
234*c8dee2aaSAndroid Build Coastguard Worker     if (fUsesLocalCoords && !fHead->fDrawMatrix.invert(&localMatrix)) {
235*c8dee2aaSAndroid Build Coastguard Worker         return;
236*c8dee2aaSAndroid Build Coastguard Worker     }
237*c8dee2aaSAndroid Build Coastguard Worker 
238*c8dee2aaSAndroid Build Coastguard Worker     GrAtlasManager* atlasManager = target->atlasManager();
239*c8dee2aaSAndroid Build Coastguard Worker 
240*c8dee2aaSAndroid Build Coastguard Worker     MaskFormat maskFormat = this->maskFormat();
241*c8dee2aaSAndroid Build Coastguard Worker 
242*c8dee2aaSAndroid Build Coastguard Worker     unsigned int numActiveViews;
243*c8dee2aaSAndroid Build Coastguard Worker     const GrSurfaceProxyView* views = atlasManager->getViews(maskFormat, &numActiveViews);
244*c8dee2aaSAndroid Build Coastguard Worker     if (!views) {
245*c8dee2aaSAndroid Build Coastguard Worker         SkDebugf("Could not allocate backing texture for atlas\n");
246*c8dee2aaSAndroid Build Coastguard Worker         return;
247*c8dee2aaSAndroid Build Coastguard Worker     }
248*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(views[0].proxy());
249*c8dee2aaSAndroid Build Coastguard Worker 
250*c8dee2aaSAndroid Build Coastguard Worker     static constexpr int kMaxTextures = GrBitmapTextGeoProc::kMaxTextures;
251*c8dee2aaSAndroid Build Coastguard Worker #if !defined(SK_DISABLE_SDF_TEXT)
252*c8dee2aaSAndroid Build Coastguard Worker     static_assert(GrDistanceFieldA8TextGeoProc::kMaxTextures == kMaxTextures);
253*c8dee2aaSAndroid Build Coastguard Worker     static_assert(GrDistanceFieldLCDTextGeoProc::kMaxTextures == kMaxTextures);
254*c8dee2aaSAndroid Build Coastguard Worker #endif
255*c8dee2aaSAndroid Build Coastguard Worker 
256*c8dee2aaSAndroid Build Coastguard Worker     auto primProcProxies = target->allocPrimProcProxyPtrs(kMaxTextures);
257*c8dee2aaSAndroid Build Coastguard Worker     for (unsigned i = 0; i < numActiveViews; ++i) {
258*c8dee2aaSAndroid Build Coastguard Worker         primProcProxies[i] = views[i].proxy();
259*c8dee2aaSAndroid Build Coastguard Worker         // This op does not know its atlas proxies when it is added to a OpsTasks, so the proxies
260*c8dee2aaSAndroid Build Coastguard Worker         // don't get added during the visitProxies call. Thus we add them here.
261*c8dee2aaSAndroid Build Coastguard Worker         target->sampledProxyArray()->push_back(views[i].proxy());
262*c8dee2aaSAndroid Build Coastguard Worker     }
263*c8dee2aaSAndroid Build Coastguard Worker 
264*c8dee2aaSAndroid Build Coastguard Worker     FlushInfo flushInfo;
265*c8dee2aaSAndroid Build Coastguard Worker     flushInfo.fPrimProcProxies = primProcProxies;
266*c8dee2aaSAndroid Build Coastguard Worker     flushInfo.fIndexBuffer = resourceProvider->refNonAAQuadIndexBuffer();
267*c8dee2aaSAndroid Build Coastguard Worker 
268*c8dee2aaSAndroid Build Coastguard Worker #if !defined(SK_DISABLE_SDF_TEXT)
269*c8dee2aaSAndroid Build Coastguard Worker     if (this->usesDistanceFields()) {
270*c8dee2aaSAndroid Build Coastguard Worker         flushInfo.fGeometryProcessor = this->setupDfProcessor(target->allocator(),
271*c8dee2aaSAndroid Build Coastguard Worker                                                               *target->caps().shaderCaps(),
272*c8dee2aaSAndroid Build Coastguard Worker                                                               localMatrix, views, numActiveViews);
273*c8dee2aaSAndroid Build Coastguard Worker     } else
274*c8dee2aaSAndroid Build Coastguard Worker #endif
275*c8dee2aaSAndroid Build Coastguard Worker     {
276*c8dee2aaSAndroid Build Coastguard Worker         auto filter = fNeedsGlyphTransform ? GrSamplerState::Filter::kLinear
277*c8dee2aaSAndroid Build Coastguard Worker                                            : GrSamplerState::Filter::kNearest;
278*c8dee2aaSAndroid Build Coastguard Worker         // Bitmap text uses a single color, combineIfPossible ensures all geometries have the same
279*c8dee2aaSAndroid Build Coastguard Worker         // color, so we can use the first's without worry.
280*c8dee2aaSAndroid Build Coastguard Worker         flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make(
281*c8dee2aaSAndroid Build Coastguard Worker                 target->allocator(), *target->caps().shaderCaps(), fHead->fColor,
282*c8dee2aaSAndroid Build Coastguard Worker                 /*wideColor=*/false, fColorSpaceXform, views, numActiveViews, filter,
283*c8dee2aaSAndroid Build Coastguard Worker                 maskFormat, localMatrix, fHasPerspective);
284*c8dee2aaSAndroid Build Coastguard Worker     }
285*c8dee2aaSAndroid Build Coastguard Worker 
286*c8dee2aaSAndroid Build Coastguard Worker     const int vertexStride = (int)flushInfo.fGeometryProcessor->vertexStride();
287*c8dee2aaSAndroid Build Coastguard Worker 
288*c8dee2aaSAndroid Build Coastguard Worker     // Ensure we don't request an insanely large contiguous vertex allocation.
289*c8dee2aaSAndroid Build Coastguard Worker     static const int kMaxVertexBytes = GrBufferAllocPool::kDefaultBufferSize;
290*c8dee2aaSAndroid Build Coastguard Worker     const int quadSize = vertexStride * kVerticesPerGlyph;
291*c8dee2aaSAndroid Build Coastguard Worker     const int maxQuadsPerBuffer = kMaxVertexBytes / quadSize;
292*c8dee2aaSAndroid Build Coastguard Worker 
293*c8dee2aaSAndroid Build Coastguard Worker     int allGlyphsCursor = 0;
294*c8dee2aaSAndroid Build Coastguard Worker     const int allGlyphsEnd = fNumGlyphs;
295*c8dee2aaSAndroid Build Coastguard Worker     int quadCursor;
296*c8dee2aaSAndroid Build Coastguard Worker     int quadEnd;
297*c8dee2aaSAndroid Build Coastguard Worker     char* vertices;
298*c8dee2aaSAndroid Build Coastguard Worker 
299*c8dee2aaSAndroid Build Coastguard Worker     auto resetVertexBuffer = [&] {
300*c8dee2aaSAndroid Build Coastguard Worker         quadCursor = 0;
301*c8dee2aaSAndroid Build Coastguard Worker         quadEnd = std::min(maxQuadsPerBuffer, allGlyphsEnd - allGlyphsCursor);
302*c8dee2aaSAndroid Build Coastguard Worker 
303*c8dee2aaSAndroid Build Coastguard Worker         vertices = (char*)target->makeVertexSpace(
304*c8dee2aaSAndroid Build Coastguard Worker                 vertexStride,
305*c8dee2aaSAndroid Build Coastguard Worker                 kVerticesPerGlyph * quadEnd,
306*c8dee2aaSAndroid Build Coastguard Worker                 &flushInfo.fVertexBuffer,
307*c8dee2aaSAndroid Build Coastguard Worker                 &flushInfo.fVertexOffset);
308*c8dee2aaSAndroid Build Coastguard Worker 
309*c8dee2aaSAndroid Build Coastguard Worker         if (!vertices || !flushInfo.fVertexBuffer) {
310*c8dee2aaSAndroid Build Coastguard Worker             SkDebugf("Could not allocate vertices\n");
311*c8dee2aaSAndroid Build Coastguard Worker             return false;
312*c8dee2aaSAndroid Build Coastguard Worker         }
313*c8dee2aaSAndroid Build Coastguard Worker         return true;
314*c8dee2aaSAndroid Build Coastguard Worker     };
315*c8dee2aaSAndroid Build Coastguard Worker 
316*c8dee2aaSAndroid Build Coastguard Worker     if (!resetVertexBuffer()) {
317*c8dee2aaSAndroid Build Coastguard Worker         return;
318*c8dee2aaSAndroid Build Coastguard Worker     }
319*c8dee2aaSAndroid Build Coastguard Worker 
320*c8dee2aaSAndroid Build Coastguard Worker     for (const Geometry* geo = fHead; geo != nullptr; geo = geo->fNext) {
321*c8dee2aaSAndroid Build Coastguard Worker         const sktext::gpu::AtlasSubRun& subRun = geo->fSubRun;
322*c8dee2aaSAndroid Build Coastguard Worker         SkASSERTF((int) subRun.vertexStride(geo->fDrawMatrix) == vertexStride,
323*c8dee2aaSAndroid Build Coastguard Worker                   "subRun stride: %d vertex buffer stride: %d\n",
324*c8dee2aaSAndroid Build Coastguard Worker                   (int)subRun.vertexStride(geo->fDrawMatrix), vertexStride);
325*c8dee2aaSAndroid Build Coastguard Worker 
326*c8dee2aaSAndroid Build Coastguard Worker         const int subRunEnd = subRun.glyphCount();
327*c8dee2aaSAndroid Build Coastguard Worker         auto regenerateDelegate = [&](sktext::gpu::GlyphVector* glyphs,
328*c8dee2aaSAndroid Build Coastguard Worker                                       int begin,
329*c8dee2aaSAndroid Build Coastguard Worker                                       int end,
330*c8dee2aaSAndroid Build Coastguard Worker                                       skgpu::MaskFormat maskFormat,
331*c8dee2aaSAndroid Build Coastguard Worker                                       int padding) {
332*c8dee2aaSAndroid Build Coastguard Worker             return glyphs->regenerateAtlasForGanesh(begin, end, maskFormat, padding, target);
333*c8dee2aaSAndroid Build Coastguard Worker         };
334*c8dee2aaSAndroid Build Coastguard Worker         for (int subRunCursor = 0; subRunCursor < subRunEnd;) {
335*c8dee2aaSAndroid Build Coastguard Worker             // Regenerate the atlas for the remainder of the glyphs in the run, or the remainder
336*c8dee2aaSAndroid Build Coastguard Worker             // of the glyphs to fill the vertex buffer.
337*c8dee2aaSAndroid Build Coastguard Worker             int regenEnd = subRunCursor + std::min(subRunEnd - subRunCursor, quadEnd - quadCursor);
338*c8dee2aaSAndroid Build Coastguard Worker             auto[ok, glyphsRegenerated] = subRun.regenerateAtlas(subRunCursor, regenEnd,
339*c8dee2aaSAndroid Build Coastguard Worker                                                                  regenerateDelegate);
340*c8dee2aaSAndroid Build Coastguard Worker             // There was a problem allocating the glyph in the atlas. Bail.
341*c8dee2aaSAndroid Build Coastguard Worker             if (!ok) {
342*c8dee2aaSAndroid Build Coastguard Worker                 return;
343*c8dee2aaSAndroid Build Coastguard Worker             }
344*c8dee2aaSAndroid Build Coastguard Worker 
345*c8dee2aaSAndroid Build Coastguard Worker             geo->fillVertexData(vertices + quadCursor * quadSize, subRunCursor, glyphsRegenerated);
346*c8dee2aaSAndroid Build Coastguard Worker 
347*c8dee2aaSAndroid Build Coastguard Worker             subRunCursor += glyphsRegenerated;
348*c8dee2aaSAndroid Build Coastguard Worker             quadCursor += glyphsRegenerated;
349*c8dee2aaSAndroid Build Coastguard Worker             allGlyphsCursor += glyphsRegenerated;
350*c8dee2aaSAndroid Build Coastguard Worker             flushInfo.fGlyphsToFlush += glyphsRegenerated;
351*c8dee2aaSAndroid Build Coastguard Worker 
352*c8dee2aaSAndroid Build Coastguard Worker             if (quadCursor == quadEnd || subRunCursor < subRunEnd) {
353*c8dee2aaSAndroid Build Coastguard Worker                 // Flush if not all the glyphs are drawn because either the quad buffer is full or
354*c8dee2aaSAndroid Build Coastguard Worker                 // the atlas is out of space.
355*c8dee2aaSAndroid Build Coastguard Worker                 if (subRunCursor < subRunEnd) {
356*c8dee2aaSAndroid Build Coastguard Worker                     ATRACE_ANDROID_FRAMEWORK_ALWAYS("Atlas full");
357*c8dee2aaSAndroid Build Coastguard Worker                 }
358*c8dee2aaSAndroid Build Coastguard Worker                 this->createDrawForGeneratedGlyphs(target, &flushInfo);
359*c8dee2aaSAndroid Build Coastguard Worker                 if (quadCursor == quadEnd && allGlyphsCursor < allGlyphsEnd) {
360*c8dee2aaSAndroid Build Coastguard Worker                     // If the vertex buffer is full and there are still glyphs to draw then
361*c8dee2aaSAndroid Build Coastguard Worker                     // get a new buffer.
362*c8dee2aaSAndroid Build Coastguard Worker                     if(!resetVertexBuffer()) {
363*c8dee2aaSAndroid Build Coastguard Worker                         return;
364*c8dee2aaSAndroid Build Coastguard Worker                     }
365*c8dee2aaSAndroid Build Coastguard Worker                 }
366*c8dee2aaSAndroid Build Coastguard Worker             }
367*c8dee2aaSAndroid Build Coastguard Worker         }
368*c8dee2aaSAndroid Build Coastguard Worker     }
369*c8dee2aaSAndroid Build Coastguard Worker }
370*c8dee2aaSAndroid Build Coastguard Worker 
onExecute(GrOpFlushState * flushState,const SkRect & chainBounds)371*c8dee2aaSAndroid Build Coastguard Worker void AtlasTextOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
372*c8dee2aaSAndroid Build Coastguard Worker     auto pipeline = GrSimpleMeshDrawOpHelper::CreatePipeline(flushState,
373*c8dee2aaSAndroid Build Coastguard Worker                                                              std::move(fProcessors),
374*c8dee2aaSAndroid Build Coastguard Worker                                                              GrPipeline::InputFlags::kNone);
375*c8dee2aaSAndroid Build Coastguard Worker 
376*c8dee2aaSAndroid Build Coastguard Worker     flushState->executeDrawsAndUploadsForMeshDrawOp(this, chainBounds, pipeline,
377*c8dee2aaSAndroid Build Coastguard Worker                                                     &GrUserStencilSettings::kUnused);
378*c8dee2aaSAndroid Build Coastguard Worker }
379*c8dee2aaSAndroid Build Coastguard Worker 
createDrawForGeneratedGlyphs(GrMeshDrawTarget * target,FlushInfo * flushInfo) const380*c8dee2aaSAndroid Build Coastguard Worker void AtlasTextOp::createDrawForGeneratedGlyphs(GrMeshDrawTarget* target,
381*c8dee2aaSAndroid Build Coastguard Worker                                                FlushInfo* flushInfo) const {
382*c8dee2aaSAndroid Build Coastguard Worker     if (!flushInfo->fGlyphsToFlush) {
383*c8dee2aaSAndroid Build Coastguard Worker         return;
384*c8dee2aaSAndroid Build Coastguard Worker     }
385*c8dee2aaSAndroid Build Coastguard Worker 
386*c8dee2aaSAndroid Build Coastguard Worker     auto atlasManager = target->atlasManager();
387*c8dee2aaSAndroid Build Coastguard Worker 
388*c8dee2aaSAndroid Build Coastguard Worker     GrGeometryProcessor* gp = flushInfo->fGeometryProcessor;
389*c8dee2aaSAndroid Build Coastguard Worker     MaskFormat maskFormat = this->maskFormat();
390*c8dee2aaSAndroid Build Coastguard Worker 
391*c8dee2aaSAndroid Build Coastguard Worker     unsigned int numActiveViews;
392*c8dee2aaSAndroid Build Coastguard Worker     const GrSurfaceProxyView* views = atlasManager->getViews(maskFormat, &numActiveViews);
393*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(views);
394*c8dee2aaSAndroid Build Coastguard Worker     // Something has gone terribly wrong, bail
395*c8dee2aaSAndroid Build Coastguard Worker     if (!views || 0 == numActiveViews) {
396*c8dee2aaSAndroid Build Coastguard Worker         return;
397*c8dee2aaSAndroid Build Coastguard Worker     }
398*c8dee2aaSAndroid Build Coastguard Worker     if (gp->numTextureSamplers() != (int) numActiveViews) {
399*c8dee2aaSAndroid Build Coastguard Worker         // During preparation the number of atlas pages has increased.
400*c8dee2aaSAndroid Build Coastguard Worker         // Update the proxies used in the GP to match.
401*c8dee2aaSAndroid Build Coastguard Worker         for (unsigned i = gp->numTextureSamplers(); i < numActiveViews; ++i) {
402*c8dee2aaSAndroid Build Coastguard Worker             flushInfo->fPrimProcProxies[i] = views[i].proxy();
403*c8dee2aaSAndroid Build Coastguard Worker             // This op does not know its atlas proxies when it is added to a OpsTasks, so the
404*c8dee2aaSAndroid Build Coastguard Worker             // proxies don't get added during the visitProxies call. Thus we add them here.
405*c8dee2aaSAndroid Build Coastguard Worker             target->sampledProxyArray()->push_back(views[i].proxy());
406*c8dee2aaSAndroid Build Coastguard Worker             // These will get unreffed when the previously recorded draws destruct.
407*c8dee2aaSAndroid Build Coastguard Worker             for (int d = 0; d < flushInfo->fNumDraws; ++d) {
408*c8dee2aaSAndroid Build Coastguard Worker                 flushInfo->fPrimProcProxies[i]->ref();
409*c8dee2aaSAndroid Build Coastguard Worker             }
410*c8dee2aaSAndroid Build Coastguard Worker         }
411*c8dee2aaSAndroid Build Coastguard Worker #if !defined(SK_DISABLE_SDF_TEXT)
412*c8dee2aaSAndroid Build Coastguard Worker         if (this->usesDistanceFields()) {
413*c8dee2aaSAndroid Build Coastguard Worker             if (this->isLCD()) {
414*c8dee2aaSAndroid Build Coastguard Worker                 reinterpret_cast<GrDistanceFieldLCDTextGeoProc*>(gp)->addNewViews(
415*c8dee2aaSAndroid Build Coastguard Worker                         views, numActiveViews, GrSamplerState::Filter::kLinear);
416*c8dee2aaSAndroid Build Coastguard Worker             } else {
417*c8dee2aaSAndroid Build Coastguard Worker                 reinterpret_cast<GrDistanceFieldA8TextGeoProc*>(gp)->addNewViews(
418*c8dee2aaSAndroid Build Coastguard Worker                         views, numActiveViews, GrSamplerState::Filter::kLinear);
419*c8dee2aaSAndroid Build Coastguard Worker             }
420*c8dee2aaSAndroid Build Coastguard Worker         } else
421*c8dee2aaSAndroid Build Coastguard Worker #endif
422*c8dee2aaSAndroid Build Coastguard Worker         {
423*c8dee2aaSAndroid Build Coastguard Worker             auto filter = fNeedsGlyphTransform ? GrSamplerState::Filter::kLinear
424*c8dee2aaSAndroid Build Coastguard Worker                                                : GrSamplerState::Filter::kNearest;
425*c8dee2aaSAndroid Build Coastguard Worker             reinterpret_cast<GrBitmapTextGeoProc*>(gp)->addNewViews(views, numActiveViews, filter);
426*c8dee2aaSAndroid Build Coastguard Worker         }
427*c8dee2aaSAndroid Build Coastguard Worker     }
428*c8dee2aaSAndroid Build Coastguard Worker     int maxGlyphsPerDraw = static_cast<int>(flushInfo->fIndexBuffer->size() / sizeof(uint16_t) / 6);
429*c8dee2aaSAndroid Build Coastguard Worker     GrSimpleMesh* mesh = target->allocMesh();
430*c8dee2aaSAndroid Build Coastguard Worker     mesh->setIndexedPatterned(flushInfo->fIndexBuffer, kIndicesPerGlyph, flushInfo->fGlyphsToFlush,
431*c8dee2aaSAndroid Build Coastguard Worker                               maxGlyphsPerDraw, flushInfo->fVertexBuffer, kVerticesPerGlyph,
432*c8dee2aaSAndroid Build Coastguard Worker                               flushInfo->fVertexOffset);
433*c8dee2aaSAndroid Build Coastguard Worker     target->recordDraw(flushInfo->fGeometryProcessor, mesh, 1, flushInfo->fPrimProcProxies,
434*c8dee2aaSAndroid Build Coastguard Worker                        GrPrimitiveType::kTriangles);
435*c8dee2aaSAndroid Build Coastguard Worker     flushInfo->fVertexOffset += kVerticesPerGlyph * flushInfo->fGlyphsToFlush;
436*c8dee2aaSAndroid Build Coastguard Worker     flushInfo->fGlyphsToFlush = 0;
437*c8dee2aaSAndroid Build Coastguard Worker     ++flushInfo->fNumDraws;
438*c8dee2aaSAndroid Build Coastguard Worker }
439*c8dee2aaSAndroid Build Coastguard Worker 
onCombineIfPossible(GrOp * t,SkArenaAlloc *,const GrCaps & caps)440*c8dee2aaSAndroid Build Coastguard Worker GrOp::CombineResult AtlasTextOp::onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps& caps) {
441*c8dee2aaSAndroid Build Coastguard Worker     auto that = t->cast<AtlasTextOp>();
442*c8dee2aaSAndroid Build Coastguard Worker 
443*c8dee2aaSAndroid Build Coastguard Worker     if (fDFGPFlags != that->fDFGPFlags ||
444*c8dee2aaSAndroid Build Coastguard Worker         fMaskType != that->fMaskType ||
445*c8dee2aaSAndroid Build Coastguard Worker         fUsesLocalCoords != that->fUsesLocalCoords ||
446*c8dee2aaSAndroid Build Coastguard Worker         fNeedsGlyphTransform != that->fNeedsGlyphTransform ||
447*c8dee2aaSAndroid Build Coastguard Worker         fHasPerspective != that->fHasPerspective ||
448*c8dee2aaSAndroid Build Coastguard Worker         fUseGammaCorrectDistanceTable != that->fUseGammaCorrectDistanceTable) {
449*c8dee2aaSAndroid Build Coastguard Worker         // All flags must match for an op to be combined
450*c8dee2aaSAndroid Build Coastguard Worker         return CombineResult::kCannotCombine;
451*c8dee2aaSAndroid Build Coastguard Worker     }
452*c8dee2aaSAndroid Build Coastguard Worker 
453*c8dee2aaSAndroid Build Coastguard Worker     if (fProcessors != that->fProcessors) {
454*c8dee2aaSAndroid Build Coastguard Worker         return CombineResult::kCannotCombine;
455*c8dee2aaSAndroid Build Coastguard Worker     }
456*c8dee2aaSAndroid Build Coastguard Worker 
457*c8dee2aaSAndroid Build Coastguard Worker     if (fUsesLocalCoords) {
458*c8dee2aaSAndroid Build Coastguard Worker         // If the fragment processors use local coordinates, the GPs compute them using the inverse
459*c8dee2aaSAndroid Build Coastguard Worker         // of the view matrix stored in a uniform, so all geometries must have the same matrix.
460*c8dee2aaSAndroid Build Coastguard Worker         const SkMatrix& thisFirstMatrix = fHead->fDrawMatrix;
461*c8dee2aaSAndroid Build Coastguard Worker         const SkMatrix& thatFirstMatrix = that->fHead->fDrawMatrix;
462*c8dee2aaSAndroid Build Coastguard Worker         if (!SkMatrixPriv::CheapEqual(thisFirstMatrix, thatFirstMatrix)) {
463*c8dee2aaSAndroid Build Coastguard Worker             return CombineResult::kCannotCombine;
464*c8dee2aaSAndroid Build Coastguard Worker         }
465*c8dee2aaSAndroid Build Coastguard Worker     }
466*c8dee2aaSAndroid Build Coastguard Worker 
467*c8dee2aaSAndroid Build Coastguard Worker #if !defined(SK_DISABLE_SDF_TEXT)
468*c8dee2aaSAndroid Build Coastguard Worker    if (this->usesDistanceFields()) {
469*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(that->usesDistanceFields());
470*c8dee2aaSAndroid Build Coastguard Worker         if (fLuminanceColor != that->fLuminanceColor) {
471*c8dee2aaSAndroid Build Coastguard Worker             return CombineResult::kCannotCombine;
472*c8dee2aaSAndroid Build Coastguard Worker         }
473*c8dee2aaSAndroid Build Coastguard Worker     } else
474*c8dee2aaSAndroid Build Coastguard Worker #endif
475*c8dee2aaSAndroid Build Coastguard Worker     {
476*c8dee2aaSAndroid Build Coastguard Worker         if (this->maskType() == MaskType::kColorBitmap &&
477*c8dee2aaSAndroid Build Coastguard Worker             fHead->fColor != that->fHead->fColor) {
478*c8dee2aaSAndroid Build Coastguard Worker             // This ensures all merged bitmap color text ops have a constant color
479*c8dee2aaSAndroid Build Coastguard Worker             return CombineResult::kCannotCombine;
480*c8dee2aaSAndroid Build Coastguard Worker         }
481*c8dee2aaSAndroid Build Coastguard Worker     }
482*c8dee2aaSAndroid Build Coastguard Worker 
483*c8dee2aaSAndroid Build Coastguard Worker     fNumGlyphs += that->fNumGlyphs;
484*c8dee2aaSAndroid Build Coastguard Worker 
485*c8dee2aaSAndroid Build Coastguard Worker     // After concat, that's geometry list is emptied so it will not unref the blobs when destructed
486*c8dee2aaSAndroid Build Coastguard Worker     this->addGeometry(that->fHead);
487*c8dee2aaSAndroid Build Coastguard Worker     that->fHead = nullptr;
488*c8dee2aaSAndroid Build Coastguard Worker     return CombineResult::kMerged;
489*c8dee2aaSAndroid Build Coastguard Worker }
490*c8dee2aaSAndroid Build Coastguard Worker 
491*c8dee2aaSAndroid Build Coastguard Worker #if !defined(SK_DISABLE_SDF_TEXT)
setupDfProcessor(SkArenaAlloc * arena,const GrShaderCaps & caps,const SkMatrix & localMatrix,const GrSurfaceProxyView * views,unsigned int numActiveViews) const492*c8dee2aaSAndroid Build Coastguard Worker GrGeometryProcessor* AtlasTextOp::setupDfProcessor(SkArenaAlloc* arena,
493*c8dee2aaSAndroid Build Coastguard Worker                                                    const GrShaderCaps& caps,
494*c8dee2aaSAndroid Build Coastguard Worker                                                    const SkMatrix& localMatrix,
495*c8dee2aaSAndroid Build Coastguard Worker                                                    const GrSurfaceProxyView* views,
496*c8dee2aaSAndroid Build Coastguard Worker                                                    unsigned int numActiveViews) const {
497*c8dee2aaSAndroid Build Coastguard Worker     auto dfAdjustTable = sktext::gpu::DistanceFieldAdjustTable::Get();
498*c8dee2aaSAndroid Build Coastguard Worker 
499*c8dee2aaSAndroid Build Coastguard Worker     // see if we need to create a new effect
500*c8dee2aaSAndroid Build Coastguard Worker     if (this->isLCD()) {
501*c8dee2aaSAndroid Build Coastguard Worker         float redCorrection = dfAdjustTable->getAdjustment(SkColorGetR(fLuminanceColor),
502*c8dee2aaSAndroid Build Coastguard Worker                                                            fUseGammaCorrectDistanceTable);
503*c8dee2aaSAndroid Build Coastguard Worker         float greenCorrection = dfAdjustTable->getAdjustment(SkColorGetG(fLuminanceColor),
504*c8dee2aaSAndroid Build Coastguard Worker                                                              fUseGammaCorrectDistanceTable);
505*c8dee2aaSAndroid Build Coastguard Worker         float blueCorrection = dfAdjustTable->getAdjustment(SkColorGetB(fLuminanceColor),
506*c8dee2aaSAndroid Build Coastguard Worker                                                             fUseGammaCorrectDistanceTable);
507*c8dee2aaSAndroid Build Coastguard Worker         GrDistanceFieldLCDTextGeoProc::DistanceAdjust widthAdjust =
508*c8dee2aaSAndroid Build Coastguard Worker                 GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(
509*c8dee2aaSAndroid Build Coastguard Worker                         redCorrection, greenCorrection, blueCorrection);
510*c8dee2aaSAndroid Build Coastguard Worker         return GrDistanceFieldLCDTextGeoProc::Make(arena, caps, views, numActiveViews,
511*c8dee2aaSAndroid Build Coastguard Worker                                                    GrSamplerState::Filter::kLinear, widthAdjust,
512*c8dee2aaSAndroid Build Coastguard Worker                                                    fDFGPFlags, localMatrix);
513*c8dee2aaSAndroid Build Coastguard Worker     } else {
514*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_GAMMA_APPLY_TO_A8)
515*c8dee2aaSAndroid Build Coastguard Worker         float correction = 0;
516*c8dee2aaSAndroid Build Coastguard Worker         if (this->maskType() != MaskType::kAliasedDistanceField) {
517*c8dee2aaSAndroid Build Coastguard Worker             U8CPU lum = SkColorSpaceLuminance::computeLuminance(SK_GAMMA_EXPONENT, fLuminanceColor);
518*c8dee2aaSAndroid Build Coastguard Worker             correction = dfAdjustTable->getAdjustment(lum, fUseGammaCorrectDistanceTable);
519*c8dee2aaSAndroid Build Coastguard Worker         }
520*c8dee2aaSAndroid Build Coastguard Worker         return GrDistanceFieldA8TextGeoProc::Make(arena, caps, views, numActiveViews,
521*c8dee2aaSAndroid Build Coastguard Worker                                                   GrSamplerState::Filter::kLinear, correction,
522*c8dee2aaSAndroid Build Coastguard Worker                                                   fDFGPFlags, localMatrix);
523*c8dee2aaSAndroid Build Coastguard Worker #else
524*c8dee2aaSAndroid Build Coastguard Worker         return GrDistanceFieldA8TextGeoProc::Make(arena, caps, views, numActiveViews,
525*c8dee2aaSAndroid Build Coastguard Worker                                                   GrSamplerState::Filter::kLinear, fDFGPFlags,
526*c8dee2aaSAndroid Build Coastguard Worker                                                   localMatrix);
527*c8dee2aaSAndroid Build Coastguard Worker #endif
528*c8dee2aaSAndroid Build Coastguard Worker     }
529*c8dee2aaSAndroid Build Coastguard Worker }
530*c8dee2aaSAndroid Build Coastguard Worker #endif // !defined(SK_DISABLE_SDF_TEXT)
531*c8dee2aaSAndroid Build Coastguard Worker 
532*c8dee2aaSAndroid Build Coastguard Worker } // namespace skgpu::ganesh
533*c8dee2aaSAndroid Build Coastguard Worker 
534*c8dee2aaSAndroid Build Coastguard Worker 
535