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