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 TextureInfo & textureInfo)52 Recording::LazyProxyData::LazyProxyData(const TextureInfo& textureInfo) {
53 fTargetProxy = TextureProxy::MakeFullyLazy(
54 textureInfo, skgpu::Budgeted::kNo, Volatile::kYes, [this](ResourceProvider*) {
55 SkASSERT(SkToBool(fTarget));
56 return std::move(fTarget);
57 });
58 }
59
lazyProxy()60 TextureProxy* Recording::LazyProxyData::lazyProxy() { return fTargetProxy.get(); }
61
refLazyProxy()62 sk_sp<TextureProxy> Recording::LazyProxyData::refLazyProxy() { return fTargetProxy; }
63
lazyInstantiate(ResourceProvider * resourceProvider,sk_sp<Texture> texture)64 bool Recording::LazyProxyData::lazyInstantiate(ResourceProvider* resourceProvider,
65 sk_sp<Texture> texture) {
66 fTarget = std::move(texture);
67 return fTargetProxy->lazyInstantiate(resourceProvider);
68 }
69
70 ////////////////////////////////////////////////////////////////////////////////
hasNonVolatileLazyProxies() const71 bool RecordingPriv::hasNonVolatileLazyProxies() const {
72 return !fRecording->fNonVolatileLazyProxies.empty();
73 }
74
instantiateNonVolatileLazyProxies(ResourceProvider * resourceProvider)75 bool RecordingPriv::instantiateNonVolatileLazyProxies(ResourceProvider* resourceProvider) {
76 SkASSERT(this->hasNonVolatileLazyProxies());
77
78 for (const auto& proxy : fRecording->fNonVolatileLazyProxies) {
79 if (!proxy->lazyInstantiate(resourceProvider)) {
80 return false;
81 }
82 }
83
84 // Note: once all the lazy proxies have been instantiated, that's it - there are no more
85 // chances to instantiate.
86 fRecording->fNonVolatileLazyProxies.clear();
87 return true;
88 }
89
hasVolatileLazyProxies() const90 bool RecordingPriv::hasVolatileLazyProxies() const {
91 return !fRecording->fVolatileLazyProxies.empty();
92 }
93
instantiateVolatileLazyProxies(ResourceProvider * resourceProvider)94 bool RecordingPriv::instantiateVolatileLazyProxies(ResourceProvider* resourceProvider) {
95 SkASSERT(this->hasVolatileLazyProxies());
96
97 for (const auto& proxy : fRecording->fVolatileLazyProxies) {
98 if (!proxy->lazyInstantiate(resourceProvider)) {
99 return false;
100 }
101 }
102
103 return true;
104 }
105
deinstantiateVolatileLazyProxies()106 void RecordingPriv::deinstantiateVolatileLazyProxies() {
107 if (!this->hasVolatileLazyProxies()) {
108 return;
109 }
110
111 for (const auto& proxy : fRecording->fVolatileLazyProxies) {
112 SkASSERT(proxy->isVolatile());
113 proxy->deinstantiate();
114 }
115 }
116
setFailureResultForFinishedProcs()117 void RecordingPriv::setFailureResultForFinishedProcs() {
118 for (int i = 0; i < fRecording->fFinishedProcs.size(); ++i) {
119 fRecording->fFinishedProcs[i]->setFailureResult();
120 }
121 fRecording->fFinishedProcs.clear();
122 }
123
addCommands(Context * context,CommandBuffer * commandBuffer,Surface * targetSurface,SkIVector targetTranslation)124 bool RecordingPriv::addCommands(Context* context,
125 CommandBuffer* commandBuffer,
126 Surface* targetSurface,
127 SkIVector targetTranslation) {
128 AutoDeinstantiateTextureProxy autoDeinstantiateTargetProxy(
129 fRecording->fTargetProxyData ? fRecording->fTargetProxyData->lazyProxy() : nullptr);
130
131 const Texture* replayTarget = nullptr;
132 ResourceProvider* resourceProvider = context->priv().resourceProvider();
133 SkASSERT(!SkToBool(fRecording->fTargetProxyData) || SkToBool(targetSurface));
134 if (fRecording->fTargetProxyData) {
135 if (!targetSurface) {
136 SKGPU_LOG_E("No surface provided to instantiate target texture proxy.");
137 return false;
138 }
139 TextureProxy* surfaceTexture = targetSurface->backingTextureProxy();
140 if (!surfaceTexture->instantiate(resourceProvider)) {
141 SKGPU_LOG_E("Could not instantiate target texture proxy.");
142 return false;
143 }
144 if (!fRecording->fTargetProxyData->lazyInstantiate(resourceProvider,
145 surfaceTexture->refTexture())) {
146 SKGPU_LOG_E("Could not instantiate deferred texture proxy.");
147 return false;
148 }
149 replayTarget = surfaceTexture->texture();
150 }
151
152 for (size_t i = 0; i < fRecording->fExtraResourceRefs.size(); ++i) {
153 commandBuffer->trackResource(fRecording->fExtraResourceRefs[i]);
154 }
155
156 // There's no need to differentiate kSuccess and kDiscard at the root list level; if every task
157 // is discarded, the Recording will automatically be a no-op on replay while still correctly
158 // notifying any finish procs the client may have added.
159 if (fRecording->fRootTaskList->addCommands(
160 context, commandBuffer, {replayTarget, targetTranslation}) == Task::Status::kFail) {
161 return false;
162 }
163 for (int i = 0; i < fRecording->fFinishedProcs.size(); ++i) {
164 commandBuffer->addFinishedProc(std::move(fRecording->fFinishedProcs[i]));
165 }
166 fRecording->fFinishedProcs.clear();
167
168 return true;
169 }
170
addResourceRef(sk_sp<Resource> resource)171 void RecordingPriv::addResourceRef(sk_sp<Resource> resource) {
172 fRecording->fExtraResourceRefs.push_back(std::move(resource));
173 }
174
addTask(sk_sp<Task> task)175 void RecordingPriv::addTask(sk_sp<Task> task) {
176 fRecording->fRootTaskList->add(std::move(task));
177 }
178
addTasks(TaskList && tasks)179 void RecordingPriv::addTasks(TaskList&& tasks) {
180 fRecording->fRootTaskList->add(std::move(tasks));
181 }
182
183 #if defined(GRAPHITE_TEST_UTILS)
isTargetProxyInstantiated() const184 bool RecordingPriv::isTargetProxyInstantiated() const {
185 return fRecording->fTargetProxyData->lazyProxy()->isInstantiated();
186 }
187
numVolatilePromiseImages() const188 int RecordingPriv::numVolatilePromiseImages() const {
189 return fRecording->fVolatileLazyProxies.size();
190 }
191
numNonVolatilePromiseImages() const192 int RecordingPriv::numNonVolatilePromiseImages() const {
193 return fRecording->fNonVolatileLazyProxies.size();
194 }
195
hasTasks() const196 bool RecordingPriv::hasTasks() const {
197 return fRecording->fRootTaskList->hasTasks();
198 }
199 #endif
200
201 } // namespace skgpu::graphite
202