1/*
2 * Copyright 2020 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 "src/gpu/ops/SmallPathAtlasMgr.h"
9
10#include "src/gpu/geometry/GrStyledShape.h"
11#include "src/gpu/ops/SmallPathShapeData.h"
12
13#ifdef DF_PATH_TRACKING
14static int g_NumCachedShapes = 0;
15static int g_NumFreedShapes = 0;
16#endif
17
18namespace skgpu::v1 {
19
20SmallPathAtlasMgr::SmallPathAtlasMgr() {}
21
22SmallPathAtlasMgr::~SmallPathAtlasMgr() {
23    this->reset();
24}
25
26void SmallPathAtlasMgr::reset() {
27    ShapeDataList::Iter iter;
28    iter.init(fShapeList, ShapeDataList::Iter::kHead_IterStart);
29    SmallPathShapeData* shapeData;
30    while ((shapeData = iter.get())) {
31        iter.next();
32        delete shapeData;
33    }
34
35    fShapeList.reset();
36    fShapeCache.reset();
37
38#ifdef DF_PATH_TRACKING
39    SkDebugf("Cached shapes: %d, freed shapes: %d\n", g_NumCachedShapes, g_NumFreedShapes);
40#endif
41
42    fAtlas = nullptr;
43}
44
45bool SmallPathAtlasMgr::initAtlas(GrProxyProvider* proxyProvider, const GrCaps* caps) {
46    if (fAtlas) {
47        return true;
48    }
49
50    static constexpr size_t kMaxAtlasTextureBytes = 2048 * 2048;
51    static constexpr size_t kPlotWidth = 512;
52    static constexpr size_t kPlotHeight = 256;
53
54    const GrBackendFormat format = caps->getDefaultBackendFormat(GrColorType::kAlpha_8,
55                                                                 GrRenderable::kNo);
56
57    GrDrawOpAtlasConfig atlasConfig(caps->maxTextureSize(), kMaxAtlasTextureBytes);
58    SkISize size = atlasConfig.atlasDimensions(kA8_GrMaskFormat);
59#ifdef SK_ENABLE_SMALL_PAGE
60    int pageNum = 4; // The maximum number of texture pages in the original skia code is 4
61    if (atlasConfig.getARGBDimensions().width() > 512) {
62        // reset atlasConfig to suit small page.
63        pageNum = atlasConfig.resetAsSmallPage();
64    }
65#endif
66    fAtlas = GrDrawOpAtlas::Make(proxyProvider, format,
67                                 GrColorType::kAlpha_8, size.width(), size.height(),
68                                 kPlotWidth, kPlotHeight, this,
69                                 GrDrawOpAtlas::AllowMultitexturing::kYes,
70#ifdef SK_ENABLE_SMALL_PAGE
71                                 pageNum,
72#endif
73                                 this);
74
75    return SkToBool(fAtlas);
76}
77
78void SmallPathAtlasMgr::deleteCacheEntry(SmallPathShapeData* shapeData) {
79    fShapeCache.remove(shapeData->fKey);
80    fShapeList.remove(shapeData);
81    delete shapeData;
82}
83
84SmallPathShapeData* SmallPathAtlasMgr::findOrCreate(const SmallPathShapeDataKey& key) {
85    auto shapeData = fShapeCache.find(key);
86    if (!shapeData) {
87        // TODO: move the key into the ctor
88        shapeData = new SmallPathShapeData(key);
89        fShapeCache.add(shapeData);
90        fShapeList.addToTail(shapeData);
91#ifdef DF_PATH_TRACKING
92        ++g_NumCachedShapes;
93#endif
94    } else if (!fAtlas->hasID(shapeData->fAtlasLocator.plotLocator())) {
95        shapeData->fAtlasLocator.invalidatePlotLocator();
96    }
97
98    return shapeData;
99}
100
101SmallPathShapeData* SmallPathAtlasMgr::findOrCreate(const GrStyledShape& shape,
102                                                    int desiredDimension) {
103    SmallPathShapeDataKey key(shape, desiredDimension);
104
105    // TODO: move the key into 'findOrCreate'
106    return this->findOrCreate(key);
107}
108
109SmallPathShapeData* SmallPathAtlasMgr::findOrCreate(const GrStyledShape& shape,
110                                                    const SkMatrix& ctm) {
111    SmallPathShapeDataKey key(shape, ctm);
112
113    // TODO: move the key into 'findOrCreate'
114    return this->findOrCreate(key);
115}
116
117GrDrawOpAtlas::ErrorCode SmallPathAtlasMgr::addToAtlas(GrResourceProvider* resourceProvider,
118                                                       GrDeferredUploadTarget* target,
119                                                       int width, int height, const void* image,
120                                                       GrDrawOpAtlas::AtlasLocator* locator) {
121    return fAtlas->addToAtlas(resourceProvider, target, width, height, image, locator);
122}
123
124void SmallPathAtlasMgr::setUseToken(SmallPathShapeData* shapeData,
125                                    GrDeferredUploadToken token) {
126    fAtlas->setLastUseToken(shapeData->fAtlasLocator, token);
127}
128
129// Callback to clear out internal path cache when eviction occurs
130void SmallPathAtlasMgr::evict(GrDrawOpAtlas::PlotLocator plotLocator) {
131    // remove any paths that use this plot
132    ShapeDataList::Iter iter;
133    iter.init(fShapeList, ShapeDataList::Iter::kHead_IterStart);
134    SmallPathShapeData* shapeData;
135    while ((shapeData = iter.get())) {
136        iter.next();
137        if (plotLocator == shapeData->fAtlasLocator.plotLocator()) {
138            fShapeCache.remove(shapeData->fKey);
139            fShapeList.remove(shapeData);
140            delete shapeData;
141#ifdef DF_PATH_TRACKING
142            ++g_NumFreedShapes;
143#endif
144        }
145    }
146}
147
148} // namespace skgpu::v1
149