blob: 1d54029672d0d87e5c750fa1a06dbbfcfae851df [file] [log] [blame]
Jeremy Gebben4af0aa82021-09-08 09:35:16 -06001/* Copyright (c) 2015-2021 The Khronos Group Inc.
2 * Copyright (c) 2015-2021 Valve Corporation
3 * Copyright (c) 2015-2021 LunarG, Inc.
4 * Copyright (C) 2015-2021 Google Inc.
5 * Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 * Author: Courtney Goeltzenleuchter <courtneygo@google.com>
20 * Author: Tobin Ehlis <tobine@google.com>
21 * Author: Chris Forbes <chrisf@ijw.co.nz>
22 * Author: Mark Lobodzinski <mark@lunarg.com>
23 * Author: Dave Houlton <daveh@lunarg.com>
24 * Author: John Zulauf <jzulauf@lunarg.com>
25 * Author: Tobias Hector <tobias.hector@amd.com>
26 */
27#include "queue_state.h"
28#include "state_tracker.h"
29#include "cmd_buffer_state.h"
30
31void ValidationStateTracker::RecordSubmitWaitSemaphore(CB_SUBMISSION &submission, VkQueue queue, VkSemaphore semaphore,
32 uint64_t value, uint64_t next_seq) {
33 auto semaphore_state = GetSemaphoreState(semaphore);
34 if (semaphore_state) {
35 if (semaphore_state->scope == kSyncScopeInternal) {
36 SEMAPHORE_WAIT wait;
37 wait.semaphore = semaphore;
38 wait.type = semaphore_state->type;
39 if (semaphore_state->type == VK_SEMAPHORE_TYPE_BINARY) {
40 if (semaphore_state->signaler.first != VK_NULL_HANDLE) {
41 wait.queue = semaphore_state->signaler.first;
42 wait.seq = semaphore_state->signaler.second;
43 submission.waitSemaphores.emplace_back(std::move(wait));
44 semaphore_state->BeginUse();
45 }
46 semaphore_state->signaler.first = VK_NULL_HANDLE;
47 semaphore_state->signaled = false;
48 } else if (semaphore_state->payload < value) {
49 wait.queue = queue;
50 wait.seq = next_seq;
51 wait.payload = value;
52 submission.waitSemaphores.emplace_back(std::move(wait));
53 semaphore_state->BeginUse();
54 }
55 } else {
56 submission.externalSemaphores.push_back(semaphore);
57 semaphore_state->BeginUse();
58 if (semaphore_state->scope == kSyncScopeExternalTemporary) {
59 semaphore_state->scope = kSyncScopeInternal;
60 }
61 }
62 }
63}
64
65bool ValidationStateTracker::RecordSubmitSignalSemaphore(CB_SUBMISSION &submission, VkQueue queue, VkSemaphore semaphore,
66 uint64_t value, uint64_t next_seq) {
67 bool retire_early = false;
68 auto semaphore_state = GetSemaphoreState(semaphore);
69 if (semaphore_state) {
70 if (semaphore_state->scope == kSyncScopeInternal) {
71 SEMAPHORE_SIGNAL signal;
72 signal.semaphore = semaphore;
73 signal.seq = next_seq;
74 if (semaphore_state->type == VK_SEMAPHORE_TYPE_BINARY) {
75 semaphore_state->signaler.first = queue;
76 semaphore_state->signaler.second = next_seq;
77 semaphore_state->signaled = true;
78 } else {
79 signal.payload = value;
80 }
81 semaphore_state->BeginUse();
82 submission.signalSemaphores.emplace_back(std::move(signal));
83 } else {
84 // Retire work up until this submit early, we will not see the wait that corresponds to this signal
85 retire_early = true;
86 }
87 }
88 return retire_early;
89}
90
91// Submit a fence to a queue, delimiting previous fences and previous untracked
92// work by it.
93static void SubmitFence(QUEUE_STATE *pQueue, FENCE_STATE *pFence, uint64_t submitCount) {
94 pFence->state = FENCE_INFLIGHT;
95 pFence->signaler.first = pQueue->Queue();
96 pFence->signaler.second = pQueue->seq + pQueue->submissions.size() + submitCount;
97}
98
99uint64_t ValidationStateTracker::RecordSubmitFence(QUEUE_STATE *queue_state, VkFence fence, uint32_t submit_count) {
100 auto fence_state = GetFenceState(fence);
101 uint64_t early_retire_seq = 0;
102 if (fence_state) {
103 if (fence_state->scope == kSyncScopeInternal) {
104 // Mark fence in use
105 SubmitFence(queue_state, fence_state, std::max(1u, submit_count));
106 if (!submit_count) {
107 // If no submissions, but just dropping a fence on the end of the queue,
108 // record an empty submission with just the fence, so we can determine
109 // its completion.
110 CB_SUBMISSION submission;
111 submission.fence = fence;
112 queue_state->submissions.emplace_back(std::move(submission));
113 }
114 } else {
115 // Retire work up until this fence early, we will not see the wait that corresponds to this signal
116 early_retire_seq = queue_state->seq + queue_state->submissions.size();
117 }
118 }
119 return early_retire_seq;
120}
121
122void ValidationStateTracker::RetireWorkOnQueue(QUEUE_STATE *pQueue, uint64_t seq) {
123 layer_data::unordered_map<VkQueue, uint64_t> other_queue_seqs;
124 layer_data::unordered_map<VkSemaphore, uint64_t> timeline_semaphore_counters;
125
126 // Roll this queue forward, one submission at a time.
127 while (pQueue->seq < seq) {
128 auto &submission = pQueue->submissions.front();
129
130 for (auto &wait : submission.waitSemaphores) {
131 auto semaphore_state = GetSemaphoreState(wait.semaphore);
132 if (semaphore_state) {
133 semaphore_state->EndUse();
134 }
135 if (wait.type == VK_SEMAPHORE_TYPE_TIMELINE) {
136 auto &last_counter = timeline_semaphore_counters[wait.semaphore];
137 last_counter = std::max(last_counter, wait.payload);
138 } else {
139 auto &last_seq = other_queue_seqs[wait.queue];
140 last_seq = std::max(last_seq, wait.seq);
141 }
142 }
143
144 for (auto &signal : submission.signalSemaphores) {
145 auto semaphore_state = GetSemaphoreState(signal.semaphore);
146 if (semaphore_state) {
147 semaphore_state->EndUse();
148 if (semaphore_state->type == VK_SEMAPHORE_TYPE_TIMELINE && semaphore_state->payload < signal.payload) {
149 semaphore_state->payload = signal.payload;
150 }
151 }
152 }
153
154 for (auto &semaphore : submission.externalSemaphores) {
155 auto semaphore_state = GetSemaphoreState(semaphore);
156 if (semaphore_state) {
157 semaphore_state->EndUse();
158 }
159 }
160
161 for (auto cb : submission.cbs) {
162 auto cb_node = Get<CMD_BUFFER_STATE>(cb);
163 if (!cb_node) {
164 continue;
165 }
166 // First perform decrement on general case bound objects
167 for (auto event : cb_node->writeEventsBeforeWait) {
168 auto event_node = eventMap.find(event);
169 if (event_node != eventMap.end()) {
170 event_node->second->write_in_use--;
171 }
172 }
173 QueryMap local_query_to_state_map;
174 VkQueryPool first_pool = VK_NULL_HANDLE;
175 for (auto &function : cb_node->queryUpdates) {
176 function(nullptr, /*do_validate*/ false, first_pool, submission.perf_submit_pass, &local_query_to_state_map);
177 }
178
179 for (const auto &query_state_pair : local_query_to_state_map) {
180 if (query_state_pair.second == QUERYSTATE_ENDED) {
181 queryToStateMap[query_state_pair.first] = QUERYSTATE_AVAILABLE;
182 }
183 }
184 if (cb_node->createInfo.level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
185 cb_node->EndUse();
186 }
187 }
188
189 auto fence_state = GetFenceState(submission.fence);
190 if (fence_state && fence_state->scope == kSyncScopeInternal) {
191 fence_state->state = FENCE_RETIRED;
192 }
193
194 pQueue->submissions.pop_front();
195 pQueue->seq++;
196 }
197
198 // Roll other queues forward to the highest seq we saw a wait for
199 for (const auto &qs : other_queue_seqs) {
200 RetireWorkOnQueue(GetQueueState(qs.first), qs.second);
201 }
202 for (const auto &sc : timeline_semaphore_counters) {
203 RetireTimelineSemaphore(sc.first, sc.second);
204 }
205}
206
207void ValidationStateTracker::RetireFence(VkFence fence) {
208 auto fence_state = GetFenceState(fence);
209 if (fence_state && fence_state->scope == kSyncScopeInternal) {
210 if (fence_state->signaler.first != VK_NULL_HANDLE) {
211 // Fence signaller is a queue -- use this as proof that prior operations on that queue have completed.
212 RetireWorkOnQueue(GetQueueState(fence_state->signaler.first), fence_state->signaler.second);
213 } else {
214 // Fence signaller is the WSI. We're not tracking what the WSI op actually /was/ in CV yet, but we need to mark
215 // the fence as retired.
216 fence_state->state = FENCE_RETIRED;
217 }
218 }
219}
220
221void ValidationStateTracker::RetireTimelineSemaphore(VkSemaphore semaphore, uint64_t until_payload) {
222 auto semaphore_state = GetSemaphoreState(semaphore);
223 if (semaphore_state) {
224 for (const auto &pair : queueMap) {
225 const auto &queue_state = pair.second;
226 uint64_t max_seq = 0;
227 for (const auto &submission : queue_state->submissions) {
228 for (const auto &signal_semaphore : submission.signalSemaphores) {
229 if (signal_semaphore.semaphore == semaphore && signal_semaphore.payload <= until_payload) {
230 if (signal_semaphore.seq > max_seq) {
231 max_seq = signal_semaphore.seq;
232 }
233 }
234 }
235 }
236 if (max_seq) {
237 RetireWorkOnQueue(queue_state.get(), max_seq);
238 }
239 }
240 }
241}