xref: /aosp_15_r20/external/skia/src/gpu/graphite/Recording.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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/Recording.h"
9 
10 #include "src/core/SkChecksum.h"
11 #include "src/gpu/RefCntedCallback.h"
12 #include "src/gpu/graphite/CommandBuffer.h"
13 #include "src/gpu/graphite/ContextPriv.h"
14 #include "src/gpu/graphite/Log.h"
15 #include "src/gpu/graphite/RecordingPriv.h"
16 #include "src/gpu/graphite/Resource.h"
17 #include "src/gpu/graphite/ResourceProvider.h"
18 #include "src/gpu/graphite/Surface_Graphite.h"
19 #include "src/gpu/graphite/Texture.h"
20 #include "src/gpu/graphite/TextureProxy.h"
21 #include "src/gpu/graphite/task/TaskList.h"
22 
23 #include <unordered_set>
24 
25 using namespace skia_private;
26 
27 namespace skgpu::graphite {
28 
Recording(uint32_t uniqueID,uint32_t recorderID,std::unordered_set<sk_sp<TextureProxy>,ProxyHash> && nonVolatileLazyProxies,std::unordered_set<sk_sp<TextureProxy>,ProxyHash> && volatileLazyProxies,std::unique_ptr<LazyProxyData> targetProxyData,TArray<sk_sp<RefCntedCallback>> && finishedProcs)29 Recording::Recording(uint32_t uniqueID,
30                      uint32_t recorderID,
31                      std::unordered_set<sk_sp<TextureProxy>, ProxyHash>&& nonVolatileLazyProxies,
32                      std::unordered_set<sk_sp<TextureProxy>, ProxyHash>&& volatileLazyProxies,
33                      std::unique_ptr<LazyProxyData> targetProxyData,
34                      TArray<sk_sp<RefCntedCallback>>&& finishedProcs)
35         : fUniqueID(uniqueID)
36         , fRecorderID(recorderID)
37         , fRootTaskList(new TaskList)
38         , fNonVolatileLazyProxies(std::move(nonVolatileLazyProxies))
39         , fVolatileLazyProxies(std::move(volatileLazyProxies))
40         , fTargetProxyData(std::move(targetProxyData))
41         , fFinishedProcs(std::move(finishedProcs)) {}
42 
~Recording()43 Recording::~Recording() {
44     // Any finished procs that haven't been passed to a CommandBuffer fail
45     this->priv().setFailureResultForFinishedProcs();
46 }
47 
operator ()(const sk_sp<TextureProxy> & proxy) const48 std::size_t Recording::ProxyHash::operator()(const sk_sp<TextureProxy> &proxy) const {
49     return SkGoodHash()(proxy.get());
50 }
51 
LazyProxyData(const Caps * caps,SkISize dimensions,const TextureInfo & textureInfo)52 Recording::LazyProxyData::LazyProxyData(const Caps* caps,
53                                         SkISize dimensions,
54                                         const TextureInfo& textureInfo) {
55     auto onInstantiate = [this](ResourceProvider*) {
56         SkASSERT(SkToBool(fTarget));
57         return std::move(fTarget);
58     };
59 
60     // If the texture info specifies that mipmapping is required, that implies that the final
61     // surface used to instantiate this proxy will be mipmapped, and that the dimensions of that
62     // surface are known already.
63     fTargetProxy = textureInfo.mipmapped() == Mipmapped::kYes
64                            ? TextureProxy::MakeLazy(caps,
65                                                     dimensions,
66                                                     textureInfo,
67                                                     skgpu::Budgeted::kNo,
68                                                     Volatile::kYes,
69                                                     std::move(onInstantiate))
70                            : TextureProxy::MakeFullyLazy(textureInfo,
71                                                          skgpu::Budgeted::kNo,
72                                                          Volatile::kYes,
73                                                          std::move(onInstantiate));
74 }
75 
lazyProxy()76 TextureProxy* Recording::LazyProxyData::lazyProxy() { return fTargetProxy.get(); }
77 
refLazyProxy()78 sk_sp<TextureProxy> Recording::LazyProxyData::refLazyProxy() { return fTargetProxy; }
79 
lazyInstantiate(ResourceProvider * resourceProvider,sk_sp<Texture> texture)80 bool Recording::LazyProxyData::lazyInstantiate(ResourceProvider* resourceProvider,
81                                                sk_sp<Texture> texture) {
82     fTarget = std::move(texture);
83     return fTargetProxy->lazyInstantiate(resourceProvider);
84 }
85 
86 ////////////////////////////////////////////////////////////////////////////////
hasNonVolatileLazyProxies() const87 bool RecordingPriv::hasNonVolatileLazyProxies() const {
88     return !fRecording->fNonVolatileLazyProxies.empty();
89 }
90 
instantiateNonVolatileLazyProxies(ResourceProvider * resourceProvider)91 bool RecordingPriv::instantiateNonVolatileLazyProxies(ResourceProvider* resourceProvider) {
92     SkASSERT(this->hasNonVolatileLazyProxies());
93 
94     for (const auto& proxy : fRecording->fNonVolatileLazyProxies) {
95         if (!proxy->lazyInstantiate(resourceProvider)) {
96             return false;
97         }
98     }
99 
100     // Note: once all the lazy proxies have been instantiated, that's it - there are no more
101     // chances to instantiate.
102     fRecording->fNonVolatileLazyProxies.clear();
103     return true;
104 }
105 
hasVolatileLazyProxies() const106 bool RecordingPriv::hasVolatileLazyProxies() const {
107     return !fRecording->fVolatileLazyProxies.empty();
108 }
109 
instantiateVolatileLazyProxies(ResourceProvider * resourceProvider)110 bool RecordingPriv::instantiateVolatileLazyProxies(ResourceProvider* resourceProvider) {
111     SkASSERT(this->hasVolatileLazyProxies());
112 
113     for (const auto& proxy : fRecording->fVolatileLazyProxies) {
114         if (!proxy->lazyInstantiate(resourceProvider)) {
115             return false;
116         }
117     }
118 
119     return true;
120 }
121 
deinstantiateVolatileLazyProxies()122 void RecordingPriv::deinstantiateVolatileLazyProxies() {
123     if (!this->hasVolatileLazyProxies()) {
124         return;
125     }
126 
127     for (const auto& proxy : fRecording->fVolatileLazyProxies) {
128         SkASSERT(proxy->isVolatile());
129         proxy->deinstantiate();
130     }
131 }
132 
setFailureResultForFinishedProcs()133 void RecordingPriv::setFailureResultForFinishedProcs() {
134     for (int i = 0; i < fRecording->fFinishedProcs.size(); ++i) {
135         fRecording->fFinishedProcs[i]->setFailureResult();
136     }
137     fRecording->fFinishedProcs.clear();
138 }
139 
deferredTargetProxy()140 TextureProxy* RecordingPriv::deferredTargetProxy() {
141     return fRecording->fTargetProxyData ? fRecording->fTargetProxyData->lazyProxy() : nullptr;
142 }
143 
setupDeferredTarget(ResourceProvider * resourceProvider,Surface * targetSurface,SkIVector targetTranslation,SkIRect targetClip)144 const Texture* RecordingPriv::setupDeferredTarget(ResourceProvider* resourceProvider,
145                                                   Surface* targetSurface,
146                                                   SkIVector targetTranslation,
147                                                   SkIRect targetClip) {
148     SkASSERT(targetSurface && fRecording->fTargetProxyData);
149 
150     TextureProxy* surfaceTexture = targetSurface->backingTextureProxy();
151     SkASSERT(surfaceTexture->isInstantiated());
152 
153     const TextureProxy* targetProxy = fRecording->fTargetProxyData->lazyProxy();
154     if (surfaceTexture->mipmapped() != targetProxy->mipmapped()) {
155         SKGPU_LOG_E("Deferred canvas mipmap settings don't match instantiating target's.");
156         return nullptr;
157     }
158 
159     // If the deferred canvas's texture proxy is not fully lazy, that means we used it for draws
160     // that require specific dimensions and no translation. The only time this happens is when a
161     // client requests a mipmapped deferred canvas and we automatically insert commands to
162     // regenerate mipmaps.
163     if (!targetProxy->isFullyLazy()) {
164         SkASSERT(targetProxy->mipmapped() == skgpu::Mipmapped::kYes);
165         if (targetProxy->dimensions() != surfaceTexture->dimensions()) {
166             SKGPU_LOG_E(
167                     "Deferred canvas dimensions don't match instantiating target's dimensions.");
168             return nullptr;
169         }
170         if (!targetTranslation.isZero()) {
171             SKGPU_LOG_E(
172                     "Replay translation is not allowed when replaying draws to a mipmapped "
173                     "deferred canvas.");
174             return nullptr;
175         }
176         if (!targetClip.isEmpty()) {
177             SKGPU_LOG_E(
178                     "Replay clip is not allowed when replaying draws to a mipmapped deferred "
179                     "canvas.");
180             return nullptr;
181         }
182     }
183 
184     if (!fRecording->fTargetProxyData->lazyInstantiate(resourceProvider,
185                                                        surfaceTexture->refTexture())) {
186         SKGPU_LOG_E("Could not instantiate deferred texture proxy.");
187         return nullptr;
188     }
189     return surfaceTexture->texture();
190 }
191 
addCommands(Context * context,CommandBuffer * commandBuffer,const Texture * replayTarget,SkIVector targetTranslation,SkIRect targetClip)192 bool RecordingPriv::addCommands(Context* context,
193                                 CommandBuffer* commandBuffer,
194                                 const Texture* replayTarget,
195                                 SkIVector targetTranslation,
196                                 SkIRect targetClip) {
197     for (size_t i = 0; i < fRecording->fExtraResourceRefs.size(); ++i) {
198         commandBuffer->trackResource(fRecording->fExtraResourceRefs[i]);
199     }
200 
201     // There's no need to differentiate kSuccess and kDiscard at the root list level; if every task
202     // is discarded, the Recording will automatically be a no-op on replay while still correctly
203     // notifying any finish procs the client may have added.
204     if (fRecording->fRootTaskList->addCommands(
205                 context, commandBuffer, {replayTarget, targetTranslation, targetClip}) ==
206         Task::Status::kFail) {
207         return false;
208     }
209     for (int i = 0; i < fRecording->fFinishedProcs.size(); ++i) {
210         commandBuffer->addFinishedProc(std::move(fRecording->fFinishedProcs[i]));
211     }
212     fRecording->fFinishedProcs.clear();
213 
214     return true;
215 }
216 
addResourceRef(sk_sp<Resource> resource)217 void RecordingPriv::addResourceRef(sk_sp<Resource> resource) {
218     fRecording->fExtraResourceRefs.push_back(std::move(resource));
219 }
220 
221 #if defined(GPU_TEST_UTILS)
isTargetProxyInstantiated() const222 bool RecordingPriv::isTargetProxyInstantiated() const {
223     return fRecording->fTargetProxyData->lazyProxy()->isInstantiated();
224 }
225 
numVolatilePromiseImages() const226 int RecordingPriv::numVolatilePromiseImages() const {
227     return fRecording->fVolatileLazyProxies.size();
228 }
229 
numNonVolatilePromiseImages() const230 int RecordingPriv::numNonVolatilePromiseImages() const {
231     return fRecording->fNonVolatileLazyProxies.size();
232 }
233 
hasTasks() const234 bool RecordingPriv::hasTasks() const {
235     return fRecording->fRootTaskList->hasTasks();
236 }
237 #endif
238 
239 } // namespace skgpu::graphite
240