• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 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 "include/gpu/graphite/Recorder.h"
9 
10 #include "include/core/SkCanvas.h"
11 #include "include/effects/SkRuntimeEffect.h"
12 #include "include/gpu/graphite/BackendTexture.h"
13 #include "include/gpu/graphite/GraphiteTypes.h"
14 #include "include/gpu/graphite/ImageProvider.h"
15 #include "include/gpu/graphite/Recording.h"
16 
17 #include "src/core/SkConvertPixels.h"
18 #include "src/gpu/AtlasTypes.h"
19 #include "src/gpu/graphite/BufferManager.h"
20 #include "src/gpu/graphite/Caps.h"
21 #include "src/gpu/graphite/CommandBuffer.h"
22 #include "src/gpu/graphite/ContextPriv.h"
23 #include "src/gpu/graphite/CopyTask.h"
24 #include "src/gpu/graphite/Device.h"
25 #include "src/gpu/graphite/GlobalCache.h"
26 #include "src/gpu/graphite/Log.h"
27 #include "src/gpu/graphite/PipelineData.h"
28 #include "src/gpu/graphite/PipelineDataCache.h"
29 #include "src/gpu/graphite/RecorderPriv.h"
30 #include "src/gpu/graphite/ResourceProvider.h"
31 #include "src/gpu/graphite/RuntimeEffectDictionary.h"
32 #include "src/gpu/graphite/SharedContext.h"
33 #include "src/gpu/graphite/TaskGraph.h"
34 #include "src/gpu/graphite/Texture.h"
35 #include "src/gpu/graphite/UploadBufferManager.h"
36 #include "src/gpu/graphite/UploadTask.h"
37 #include "src/gpu/graphite/text/AtlasManager.h"
38 #include "src/image/SkImage_Base.h"
39 #include "src/text/gpu/StrikeCache.h"
40 #include "src/text/gpu/TextBlobRedrawCoordinator.h"
41 
42 namespace skgpu::graphite {
43 
44 #define ASSERT_SINGLE_OWNER SKGPU_ASSERT_SINGLE_OWNER(this->singleOwner())
45 #define ASSERT_SINGLE_OWNER_PRIV SKGPU_ASSERT_SINGLE_OWNER(fRecorder->singleOwner())
46 
47 /*
48  * The default image provider doesn't perform any conversion so, by default, Graphite won't
49  * draw any non-Graphite-backed images.
50  */
51 class DefaultImageProvider final : public ImageProvider {
52 public:
Make()53     static sk_sp<DefaultImageProvider> Make() {
54         return sk_ref_sp(new DefaultImageProvider);
55     }
56 
findOrCreate(Recorder * recorder,const SkImage * image,SkImage::RequiredImageProperties)57     sk_sp<SkImage> findOrCreate(Recorder* recorder,
58                                 const SkImage* image,
59                                 SkImage::RequiredImageProperties) override {
60         SkASSERT(!as_IB(image)->isGraphiteBacked());
61 
62         return nullptr;
63     }
64 
65 private:
DefaultImageProvider()66     DefaultImageProvider() {}
67 };
68 
69 /**************************************************************************************************/
70 RecorderOptions::RecorderOptions() = default;
71 RecorderOptions::RecorderOptions(const RecorderOptions&) = default;
72 RecorderOptions::~RecorderOptions() = default;
73 
74 /**************************************************************************************************/
next_id()75 static int32_t next_id() {
76     static std::atomic<int32_t> nextID{1};
77     int32_t id;
78     do {
79         id = nextID.fetch_add(1, std::memory_order_relaxed);
80     } while (id == SK_InvalidGenID);
81     return id;
82 }
83 
Recorder(sk_sp<SharedContext> sharedContext,const RecorderOptions & options)84 Recorder::Recorder(sk_sp<SharedContext> sharedContext,
85                    const RecorderOptions& options)
86         : fSharedContext(std::move(sharedContext))
87         , fRuntimeEffectDict(std::make_unique<RuntimeEffectDictionary>())
88         , fGraph(new TaskGraph)
89         , fUniformDataCache(new UniformDataCache)
90         , fTextureDataCache(new TextureDataCache)
91         , fRecorderID(next_id())
92         , fAtlasManager(std::make_unique<AtlasManager>(this))
93         , fTokenTracker(std::make_unique<TokenTracker>())
94         , fStrikeCache(std::make_unique<sktext::gpu::StrikeCache>())
95         , fTextBlobCache(std::make_unique<sktext::gpu::TextBlobRedrawCoordinator>(fRecorderID)) {
96 
97     fClientImageProvider = options.fImageProvider;
98     if (!fClientImageProvider) {
99         fClientImageProvider = DefaultImageProvider::Make();
100     }
101 
102     fResourceProvider = fSharedContext->makeResourceProvider(this->singleOwner());
103     fDrawBufferManager.reset( new DrawBufferManager(fResourceProvider.get(),
104                                                     fSharedContext->caps()));
105     fUploadBufferManager.reset(new UploadBufferManager(fResourceProvider.get(),
106                                                        fSharedContext->caps()));
107     SkASSERT(fResourceProvider);
108 }
109 
~Recorder()110 Recorder::~Recorder() {
111     ASSERT_SINGLE_OWNER
112     for (auto& device : fTrackedDevices) {
113         device->abandonRecorder();
114     }
115 #if GRAPHITE_TEST_UTILS
116     if (fContext) {
117         fContext->priv().deregisterRecorder(this);
118     }
119 #endif
120 
121     // TODO: needed?
122     fStrikeCache->freeAll();
123 }
124 
backend() const125 BackendApi Recorder::backend() const { return fSharedContext->backend(); }
126 
snap()127 std::unique_ptr<Recording> Recorder::snap() {
128     ASSERT_SINGLE_OWNER
129     for (auto& device : fTrackedDevices) {
130         device->flushPendingWorkToRecorder();
131     }
132 
133     std::unordered_set<sk_sp<TextureProxy>, Recording::ProxyHash> nonVolatileLazyProxies;
134     std::unordered_set<sk_sp<TextureProxy>, Recording::ProxyHash> volatileLazyProxies;
135     fTextureDataCache->foreach([&](const TextureDataBlock* block) {
136         for (int j = 0; j < block->numTextures(); ++j) {
137             const TextureDataBlock::SampledTexture& tex = block->texture(j);
138 
139             if (tex.first->isLazy()) {
140                 if (tex.first->isVolatile()) {
141                     volatileLazyProxies.insert(tex.first);
142                 } else {
143                     nonVolatileLazyProxies.insert(tex.first);
144                 }
145             }
146         }
147     });
148 
149     // TODO: fulfill all promise images in the TextureDataCache here
150     // TODO: create all the samplers needed in the TextureDataCache here
151 
152     if (!fGraph->prepareResources(fResourceProvider.get(), fRuntimeEffectDict.get())) {
153         // Leaving 'fTrackedDevices' alone since they were flushed earlier and could still be
154         // attached to extant SkSurfaces.
155         fDrawBufferManager.reset(new DrawBufferManager(fResourceProvider.get(),
156                                                        fSharedContext->caps()));
157         fTextureDataCache = std::make_unique<TextureDataCache>();
158         // We leave the UniformDataCache alone
159         fGraph->reset();
160         fRuntimeEffectDict->reset();
161         return nullptr;
162     }
163 
164     std::unique_ptr<Recording::LazyProxyData> targetProxyData;
165     if (fTargetProxyData) {
166         targetProxyData = std::move(fTargetProxyData);
167         fTargetProxyDevice.reset();
168         fTargetProxyCanvas.reset();
169     }
170     std::unique_ptr<Recording> recording(new Recording(std::move(fGraph),
171                                                        std::move(nonVolatileLazyProxies),
172                                                        std::move(volatileLazyProxies),
173                                                        std::move(targetProxyData)));
174 
175     fDrawBufferManager->transferToRecording(recording.get());
176     fUploadBufferManager->transferToRecording(recording.get());
177 
178     fGraph = std::make_unique<TaskGraph>();
179     fRuntimeEffectDict->reset();
180     fTextureDataCache = std::make_unique<TextureDataCache>();
181 
182     // inject an initial task to maintain atlas state for next Recording
183     auto uploads = std::make_unique<UploadList>();
184     fAtlasManager->recordUploads(uploads.get(), /*useCachedUploads=*/true);
185     if (uploads->size() > 0) {
186         sk_sp<Task> uploadTask = UploadTask::Make(uploads.get());
187         this->priv().add(std::move(uploadTask));
188     }
189 
190     return recording;
191 }
192 
makeDeferredCanvas(const SkImageInfo & imageInfo,const TextureInfo & textureInfo)193 SkCanvas* Recorder::makeDeferredCanvas(const SkImageInfo& imageInfo,
194                                        const TextureInfo& textureInfo) {
195     if (fTargetProxyCanvas) {
196         // Require snapping before requesting another canvas.
197         SKGPU_LOG_W("Requested a new deferred canvas before snapping the previous one");
198         return nullptr;
199     }
200 
201     fTargetProxyData = std::make_unique<Recording::LazyProxyData>(textureInfo);
202     fTargetProxyDevice = Device::Make(this,
203                                       fTargetProxyData->refLazyProxy(),
204                                       imageInfo.dimensions(),
205                                       imageInfo.colorInfo(),
206                                       {},
207                                       false);
208     fTargetProxyCanvas = std::make_unique<SkCanvas>(fTargetProxyDevice);
209     return fTargetProxyCanvas.get();
210 }
211 
registerDevice(Device * device)212 void Recorder::registerDevice(Device* device) {
213     ASSERT_SINGLE_OWNER
214     fTrackedDevices.push_back(device);
215 }
216 
deregisterDevice(const Device * device)217 void Recorder::deregisterDevice(const Device* device) {
218     ASSERT_SINGLE_OWNER
219     for (auto it = fTrackedDevices.begin(); it != fTrackedDevices.end(); it++) {
220         if (*it == device) {
221             fTrackedDevices.erase(it);
222             return;
223         }
224     }
225 }
226 
227 #if GRAPHITE_TEST_UTILS
deviceIsRegistered(Device * device)228 bool Recorder::deviceIsRegistered(Device* device) {
229     ASSERT_SINGLE_OWNER
230     for (auto& currentDevice : fTrackedDevices) {
231         if (device == currentDevice) {
232             return true;
233         }
234     }
235     return false;
236 }
237 #endif
238 
createBackendTexture(SkISize dimensions,const TextureInfo & info)239 BackendTexture Recorder::createBackendTexture(SkISize dimensions, const TextureInfo& info) {
240     ASSERT_SINGLE_OWNER
241 
242     if (!info.isValid() || info.backend() != this->backend()) {
243         return {};
244     }
245     return fResourceProvider->createBackendTexture(dimensions, info);
246 }
247 
updateBackendTexture(const BackendTexture & backendTex,const SkPixmap srcData[],int numLevels)248 bool Recorder::updateBackendTexture(const BackendTexture& backendTex,
249                                     const SkPixmap srcData[],
250                                     int numLevels) {
251     ASSERT_SINGLE_OWNER
252 
253     if (!backendTex.isValid() || backendTex.backend() != this->backend()) {
254         return false;
255     }
256 
257     if (!srcData || numLevels <= 0) {
258         return false;
259     }
260 
261     // If the texture has MIP levels then we require that the full set is overwritten.
262     int numExpectedLevels = 1;
263     if (backendTex.info().mipmapped() == Mipmapped::kYes) {
264         numExpectedLevels = SkMipmap::ComputeLevelCount(backendTex.dimensions().width(),
265                                                         backendTex.dimensions().height()) + 1;
266     }
267     if (numLevels != numExpectedLevels) {
268         return false;
269     }
270 
271     SkColorType ct = srcData[0].colorType();
272 
273     if (!this->priv().caps()->areColorTypeAndTextureInfoCompatible(ct, backendTex.info())) {
274         return false;
275     }
276 
277     sk_sp<Texture> texture = this->priv().resourceProvider()->createWrappedTexture(backendTex);
278     if (!texture) {
279         return false;
280     }
281 
282     sk_sp<TextureProxy> proxy(new TextureProxy(std::move(texture)));
283 
284     std::vector<MipLevel> mipLevels;
285     mipLevels.resize(numLevels);
286 
287     for (int i = 0; i < numLevels; ++i) {
288         SkASSERT(srcData[i].addr());
289         SkASSERT(srcData[i].info().colorInfo() == srcData[0].info().colorInfo());
290 
291         mipLevels[i].fPixels = srcData[i].addr();
292         mipLevels[i].fRowBytes = srcData[i].rowBytes();
293     }
294 
295     // Src and dst colorInfo are the same
296     const SkColorInfo& colorInfo = srcData[0].info().colorInfo();
297     // Add UploadTask to Recorder
298     UploadInstance upload = UploadInstance::Make(this,
299                                                  std::move(proxy),
300                                                  colorInfo, colorInfo,
301                                                  mipLevels,
302                                                  SkIRect::MakeSize(backendTex.dimensions()),
303                                                  nullptr);
304     if (!upload.isValid()) {
305         SKGPU_LOG_E("Recorder::updateBackendTexture: Could not create UploadInstance");
306         return false;
307     }
308     sk_sp<Task> uploadTask = UploadTask::Make(std::move(upload));
309 
310     this->priv().add(std::move(uploadTask));
311 
312     return true;
313 }
314 
deleteBackendTexture(BackendTexture & texture)315 void Recorder::deleteBackendTexture(BackendTexture& texture) {
316     ASSERT_SINGLE_OWNER
317 
318     if (!texture.isValid() || texture.backend() != this->backend()) {
319         return;
320     }
321     fResourceProvider->deleteBackendTexture(texture);
322 }
323 
add(sk_sp<Task> task)324 void RecorderPriv::add(sk_sp<Task> task) {
325     ASSERT_SINGLE_OWNER_PRIV
326     fRecorder->fGraph->add(std::move(task));
327 }
328 
flushTrackedDevices()329 void RecorderPriv::flushTrackedDevices() {
330     ASSERT_SINGLE_OWNER_PRIV
331     for (Device* device : fRecorder->fTrackedDevices) {
332         device->flushPendingWorkToRecorder();
333     }
334 }
335 
336 #if GRAPHITE_TEST_UTILS
337 // used by the Context that created this Recorder to set a back pointer
setContext(Context * context)338 void RecorderPriv::setContext(Context* context) {
339     fRecorder->fContext = context;
340 }
341 #endif
342 
343 
344 } // namespace skgpu::graphite
345