• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 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/QueueManager.h"
9 
10 #include "include/gpu/graphite/Recording.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/GpuWorkSubmission.h"
15 #include "src/gpu/graphite/Log.h"
16 #include "src/gpu/graphite/RecordingPriv.h"
17 #include "src/gpu/graphite/Surface_Graphite.h"
18 #include "src/gpu/graphite/Task.h"
19 
20 namespace skgpu::graphite {
21 
22 // This constant determines how many OutstandingSubmissions are allocated together as a block in
23 // the deque. As such it needs to balance allocating too much memory vs. incurring
24 // allocation/deallocation thrashing. It should roughly correspond to the max number of outstanding
25 // submissions we expect to see.
26 static constexpr int kDefaultOutstandingAllocCnt = 8;
27 
QueueManager(const SharedContext * sharedContext)28 QueueManager::QueueManager(const SharedContext* sharedContext)
29         : fSharedContext(sharedContext)
30         , fOutstandingSubmissions(sizeof(OutstandingSubmission), kDefaultOutstandingAllocCnt) {
31 }
32 
~QueueManager()33 QueueManager::~QueueManager() {
34     this->checkForFinishedWork(SyncToCpu::kYes);
35 }
36 
setupCommandBuffer(ResourceProvider * resourceProvider)37 bool QueueManager::setupCommandBuffer(ResourceProvider* resourceProvider) {
38     if (!fCurrentCommandBuffer) {
39         if (fAvailableCommandBuffers.size()) {
40             fCurrentCommandBuffer = std::move(fAvailableCommandBuffers.back());
41             fAvailableCommandBuffers.pop_back();
42             if (!fCurrentCommandBuffer->setNewCommandBufferResources()) {
43                 fCurrentCommandBuffer.reset();
44             }
45         }
46     }
47     if (!fCurrentCommandBuffer) {
48         fCurrentCommandBuffer = this->getNewCommandBuffer(resourceProvider);
49     }
50     if (!fCurrentCommandBuffer) {
51         return false;
52     }
53 
54     return true;
55 }
56 
addRecording(const InsertRecordingInfo & info,Context * context)57 bool QueueManager::addRecording(const InsertRecordingInfo& info, Context* context) {
58     sk_sp<RefCntedCallback> callback;
59     if (info.fFinishedProc) {
60         callback = RefCntedCallback::Make(info.fFinishedProc, info.fFinishedContext);
61     }
62 
63     SkASSERT(info.fRecording);
64     if (!info.fRecording) {
65         if (callback) {
66             callback->setFailureResult();
67         }
68         SKGPU_LOG_E("No valid Recording passed into addRecording call");
69         return false;
70     }
71 
72     if (info.fTargetSurface &&
73         !static_cast<const SkSurface_Base*>(info.fTargetSurface)->isGraphiteBacked()) {
74         if (callback) {
75             callback->setFailureResult();
76         }
77         SKGPU_LOG_E("Target surface passed into addRecording call is not graphite-backed");
78         return false;
79     }
80 
81     auto resourceProvider = context->priv().resourceProvider();
82     if (!this->setupCommandBuffer(resourceProvider)) {
83         if (callback) {
84             callback->setFailureResult();
85         }
86         SKGPU_LOG_E("CommandBuffer creation failed");
87         return false;
88     }
89 
90     if (info.fRecording->priv().hasNonVolatileLazyProxies()) {
91         if (!info.fRecording->priv().instantiateNonVolatileLazyProxies(resourceProvider)) {
92             if (callback) {
93                 callback->setFailureResult();
94             }
95             SKGPU_LOG_E("Non-volatile PromiseImage instantiation has failed");
96             return false;
97         }
98     }
99 
100     if (info.fRecording->priv().hasVolatileLazyProxies()) {
101         if (!info.fRecording->priv().instantiateVolatileLazyProxies(resourceProvider)) {
102             if (callback) {
103                 callback->setFailureResult();
104             }
105             info.fRecording->priv().deinstantiateVolatileLazyProxies();
106             SKGPU_LOG_E("Volatile PromiseImage instantiation has failed");
107             return false;
108         }
109     }
110 
111     if (!info.fRecording->priv().addCommands(context,
112                                              fCurrentCommandBuffer.get(),
113                                              static_cast<Surface*>(info.fTargetSurface),
114                                              info.fTargetTranslation)) {
115         if (callback) {
116             callback->setFailureResult();
117         }
118         info.fRecording->priv().deinstantiateVolatileLazyProxies();
119         SKGPU_LOG_E("Adding Recording commands to the CommandBuffer has failed");
120         return false;
121     }
122 
123     if (callback) {
124         fCurrentCommandBuffer->addFinishedProc(std::move(callback));
125     }
126 
127     info.fRecording->priv().deinstantiateVolatileLazyProxies();
128     return true;
129 }
130 
addTask(Task * task,Context * context)131 bool QueueManager::addTask(Task* task,
132                            Context* context) {
133     SkASSERT(task);
134     if (!task) {
135         SKGPU_LOG_E("No valid Task passed into addTask call");
136         return false;
137     }
138 
139     if (!this->setupCommandBuffer(context->priv().resourceProvider())) {
140         SKGPU_LOG_E("CommandBuffer creation failed");
141         return false;
142     }
143 
144     if (!task->addCommands(context, fCurrentCommandBuffer.get(), {})) {
145         SKGPU_LOG_E("Adding Task commands to the CommandBuffer has failed");
146         return false;
147     }
148 
149     return true;
150 }
151 
addFinishInfo(const InsertFinishInfo & info,ResourceProvider * resourceProvider)152 bool QueueManager::addFinishInfo(const InsertFinishInfo& info,
153                                  ResourceProvider* resourceProvider) {
154     sk_sp<RefCntedCallback> callback;
155     if (info.fFinishedProc) {
156         callback = RefCntedCallback::Make(info.fFinishedProc, info.fFinishedContext);
157     }
158 
159     if (!this->setupCommandBuffer(resourceProvider)) {
160         if (callback) {
161             callback->setFailureResult();
162         }
163         SKGPU_LOG_E("CommandBuffer creation failed");
164         return false;
165     }
166 
167     if (callback) {
168         fCurrentCommandBuffer->addFinishedProc(std::move(callback));
169     }
170 
171     return true;
172 }
173 
submitToGpu()174 bool QueueManager::submitToGpu() {
175     if (!fCurrentCommandBuffer) {
176         // We warn because this probably representative of a bad client state, where they don't
177         // need to submit but didn't notice, but technically the submit itself is fine (no-op), so
178         // we return true.
179         SKGPU_LOG_W("Submit called with no active command buffer!");
180         return true;
181     }
182 
183 #ifdef SK_DEBUG
184     if (!fCurrentCommandBuffer->hasWork()) {
185         SKGPU_LOG_W("Submitting empty command buffer!");
186     }
187 #endif
188 
189     auto submission = this->onSubmitToGpu();
190     if (!submission) {
191         return false;
192     }
193 
194     new (fOutstandingSubmissions.push_back()) OutstandingSubmission(std::move(submission));
195     return true;
196 }
197 
checkForFinishedWork(SyncToCpu sync)198 void QueueManager::checkForFinishedWork(SyncToCpu sync) {
199     if (sync == SyncToCpu::kYes) {
200         // wait for the last submission to finish
201         OutstandingSubmission* back = (OutstandingSubmission*)fOutstandingSubmissions.back();
202         if (back) {
203             (*back)->waitUntilFinished();
204         }
205     }
206 
207     // Iterate over all the outstanding submissions to see if any have finished. The work
208     // submissions are in order from oldest to newest, so we start at the front to check if they
209     // have finished. If so we pop it off and move onto the next.
210     // Repeat till we find a submission that has not finished yet (and all others afterwards are
211     // also guaranteed to not have finished).
212     OutstandingSubmission* front = (OutstandingSubmission*)fOutstandingSubmissions.front();
213     while (front && (*front)->isFinished()) {
214         // Make sure we remove before deleting as deletion might try to kick off another submit
215         // (though hopefully *not* in Graphite).
216         fOutstandingSubmissions.pop_front();
217         // Since we used placement new we are responsible for calling the destructor manually.
218         front->~OutstandingSubmission();
219         front = (OutstandingSubmission*)fOutstandingSubmissions.front();
220     }
221     SkASSERT(sync == SyncToCpu::kNo || fOutstandingSubmissions.empty());
222 }
223 
returnCommandBuffer(std::unique_ptr<CommandBuffer> commandBuffer)224 void QueueManager::returnCommandBuffer(std::unique_ptr<CommandBuffer> commandBuffer) {
225     fAvailableCommandBuffers.push_back(std::move(commandBuffer));
226 }
227 
228 } // namespace skgpu::graphite
229