1 /*
2 * Copyright 2023 Google LLC
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/graphite/AtlasProvider.h"
9
10 #include "include/gpu/graphite/Recorder.h"
11 #include "src/gpu/graphite/ClipAtlasManager.h"
12 #include "src/gpu/graphite/ComputePathAtlas.h"
13 #include "src/gpu/graphite/DrawContext.h"
14 #include "src/gpu/graphite/Log.h"
15 #include "src/gpu/graphite/RasterPathAtlas.h"
16 #include "src/gpu/graphite/RecorderPriv.h"
17 #include "src/gpu/graphite/RendererProvider.h"
18 #include "src/gpu/graphite/TextureProxy.h"
19 #include "src/gpu/graphite/text/TextAtlasManager.h"
20
21 namespace skgpu::graphite {
22
QueryPathAtlasSupport(const Caps * caps)23 AtlasProvider::PathAtlasFlagsBitMask AtlasProvider::QueryPathAtlasSupport(const Caps* caps) {
24 // The raster-backend path atlas is always supported.
25 PathAtlasFlagsBitMask flags = PathAtlasFlags::kRaster;
26 if (RendererProvider::IsVelloRendererSupported(caps)) {
27 flags |= PathAtlasFlags::kCompute;
28 }
29 return flags;
30 }
31
AtlasProvider(Recorder * recorder)32 AtlasProvider::AtlasProvider(Recorder* recorder)
33 : fTextAtlasManager(std::make_unique<TextAtlasManager>(recorder))
34 , fRasterPathAtlas(std::make_unique<RasterPathAtlas>(recorder))
35 , fClipAtlasManager(std::make_unique<ClipAtlasManager>(recorder))
36 , fPathAtlasFlags(QueryPathAtlasSupport(recorder->priv().caps())) {}
37
createComputePathAtlas(Recorder * recorder) const38 std::unique_ptr<ComputePathAtlas> AtlasProvider::createComputePathAtlas(Recorder* recorder) const {
39 if (this->isAvailable(PathAtlasFlags::kCompute)) {
40 return ComputePathAtlas::CreateDefault(recorder);
41 }
42 return nullptr;
43 }
44
getRasterPathAtlas() const45 RasterPathAtlas* AtlasProvider::getRasterPathAtlas() const {
46 return fRasterPathAtlas.get();
47 }
48
getClipAtlasManager() const49 ClipAtlasManager* AtlasProvider::getClipAtlasManager() const {
50 return fClipAtlasManager.get();
51 }
52
getAtlasTexture(Recorder * recorder,uint16_t width,uint16_t height,SkColorType colorType,uint16_t identifier,bool requireStorageUsage)53 sk_sp<TextureProxy> AtlasProvider::getAtlasTexture(Recorder* recorder,
54 uint16_t width,
55 uint16_t height,
56 SkColorType colorType,
57 uint16_t identifier,
58 bool requireStorageUsage) {
59 uint64_t key = static_cast<uint64_t>(width) << 48 |
60 static_cast<uint64_t>(height) << 32 |
61 static_cast<uint64_t>(colorType) << 16 |
62 static_cast<uint64_t>(identifier);
63 auto iter = fTexturePool.find(key);
64 if (iter != fTexturePool.end()) {
65 return iter->second;
66 }
67
68 // We currently only make the distinction between a storage texture (written by a
69 // compute pass) and a plain sampleable texture (written via upload) that won't be
70 // used as a render attachment.
71 const Caps* caps = recorder->priv().caps();
72 auto textureInfo = requireStorageUsage
73 ? caps->getDefaultStorageTextureInfo(colorType)
74 : caps->getDefaultSampledTextureInfo(colorType,
75 Mipmapped::kNo,
76 recorder->priv().isProtected(),
77 Renderable::kNo);
78 sk_sp<TextureProxy> proxy = TextureProxy::Make(caps,
79 recorder->priv().resourceProvider(),
80 SkISize::Make((int32_t) width, (int32_t) height),
81 textureInfo,
82 "AtlasProviderTexture",
83 Budgeted::kYes);
84 if (!proxy) {
85 return nullptr;
86 }
87
88 fTexturePool[key] = proxy;
89 return proxy;
90 }
91
freeGpuResources()92 void AtlasProvider::freeGpuResources() {
93 // Clear out any pages not in use or needed for any pending work on the Recorder.
94 // In the event this is called right after a snap(), all pages would be eligible
95 // for cleanup anyways.
96 fTextAtlasManager->freeGpuResources();
97 if (fRasterPathAtlas) {
98 fRasterPathAtlas->freeGpuResources();
99 }
100 if (fClipAtlasManager) {
101 fClipAtlasManager->freeGpuResources();
102 }
103 // Release any textures held directly by the provider. These textures are used by transient
104 // ComputePathAtlases that are reset every time a DrawContext snaps a DrawTask so there is no
105 // need to reset those atlases explicitly here. Since the AtlasProvider gives out refs to the
106 // TextureProxies in the pool, it should be safe to clear the pool in the middle of Recording.
107 // Draws that use the previous TextureProxies will have refs on them.
108 fTexturePool.clear();
109 }
110
recordUploads(DrawContext * dc)111 void AtlasProvider::recordUploads(DrawContext* dc) {
112 if (!fTextAtlasManager->recordUploads(dc)) {
113 SKGPU_LOG_E("TextAtlasManager uploads have failed -- may see invalid results.");
114 }
115
116 if (fRasterPathAtlas) {
117 fRasterPathAtlas->recordUploads(dc);
118 }
119 if (fClipAtlasManager) {
120 fClipAtlasManager->recordUploads(dc);
121 }
122 }
123
compact()124 void AtlasProvider::compact() {
125 fTextAtlasManager->compact();
126 if (fRasterPathAtlas) {
127 fRasterPathAtlas->compact();
128 }
129 if (fClipAtlasManager) {
130 fClipAtlasManager->compact();
131 }
132 }
133
invalidateAtlases()134 void AtlasProvider::invalidateAtlases() {
135 // We must also evict atlases on a failure. The failed tasks can include uploads that the
136 // atlas was depending on for its caches. Failing to prepare means they will never run so
137 // future "successful" Recorder snaps would otherwise reference atlas pages that had stale
138 // contents.
139 fTextAtlasManager->evictAtlases();
140 if (fRasterPathAtlas) {
141 fRasterPathAtlas->evictAtlases();
142 }
143 if (fClipAtlasManager) {
144 fClipAtlasManager->evictAtlases();
145 }
146 }
147
148 } // namespace skgpu::graphite
149