blob: 5160f3fb8b3fe1a35e4d68feb6bead0a7aca019f [file] [log] [blame]
John Zulauf9cb530d2019-09-30 14:14:10 -06001/* Copyright (c) 2019 The Khronos Group Inc.
2 * Copyright (c) 2019 Valve Corporation
3 * Copyright (c) 2019 LunarG, Inc.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 * Author: John Zulauf <jzulauf@lunarg.com>
18 */
19
20#include <limits>
21#include <vector>
22#include "synchronization_validation.h"
23
24static const char *string_SyncHazardVUID(SyncHazard hazard) {
25 switch (hazard) {
26 case SyncHazard::NONE:
John Zulauf2f952d22020-02-10 11:34:51 -070027 return "SYNC-HAZARD-NONE";
John Zulauf9cb530d2019-09-30 14:14:10 -060028 break;
29 case SyncHazard::READ_AFTER_WRITE:
30 return "SYNC-HAZARD-READ_AFTER_WRITE";
31 break;
32 case SyncHazard::WRITE_AFTER_READ:
33 return "SYNC-HAZARD-WRITE_AFTER_READ";
34 break;
35 case SyncHazard::WRITE_AFTER_WRITE:
36 return "SYNC-HAZARD-WRITE_AFTER_WRITE";
37 break;
John Zulauf2f952d22020-02-10 11:34:51 -070038 case SyncHazard::READ_RACING_WRITE:
39 return "SYNC-HAZARD-READ-RACING-WRITE";
40 break;
41 case SyncHazard::WRITE_RACING_WRITE:
42 return "SYNC-HAZARD-WRITE-RACING-WRITE";
43 break;
44 case SyncHazard::WRITE_RACING_READ:
45 return "SYNC-HAZARD-WRITE-RACING-READ";
46 break;
John Zulauf9cb530d2019-09-30 14:14:10 -060047 default:
48 assert(0);
49 }
50 return "SYNC-HAZARD-INVALID";
51}
52
53static const char *string_SyncHazard(SyncHazard hazard) {
54 switch (hazard) {
55 case SyncHazard::NONE:
56 return "NONR";
57 break;
58 case SyncHazard::READ_AFTER_WRITE:
59 return "READ_AFTER_WRITE";
60 break;
61 case SyncHazard::WRITE_AFTER_READ:
62 return "WRITE_AFTER_READ";
63 break;
64 case SyncHazard::WRITE_AFTER_WRITE:
65 return "WRITE_AFTER_WRITE";
66 break;
John Zulauf2f952d22020-02-10 11:34:51 -070067 case SyncHazard::READ_RACING_WRITE:
68 return "READ_RACING_WRITE";
69 break;
70 case SyncHazard::WRITE_RACING_WRITE:
71 return "WRITE_RACING_WRITE";
72 break;
73 case SyncHazard::WRITE_RACING_READ:
74 return "WRITE_RACING_READ";
75 break;
John Zulauf9cb530d2019-09-30 14:14:10 -060076 default:
77 assert(0);
78 }
79 return "INVALID HAZARD";
80}
81
John Zulauf0cb5be22020-01-23 12:18:22 -070082// Expand the pipeline stage without regard to whether the are valid w.r.t. queue or extension
83VkPipelineStageFlags ExpandPipelineStages(VkQueueFlags queue_flags, VkPipelineStageFlags stage_mask) {
84 VkPipelineStageFlags expanded = stage_mask;
85 if (VK_PIPELINE_STAGE_ALL_COMMANDS_BIT & stage_mask) {
86 expanded = expanded & ~VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
87 for (const auto &all_commands : syncAllCommandStagesByQueueFlags) {
88 if (all_commands.first & queue_flags) {
89 expanded |= all_commands.second;
90 }
91 }
92 }
93 if (VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT & stage_mask) {
94 expanded = expanded & ~VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
95 expanded |= syncAllCommandStagesByQueueFlags.at(VK_QUEUE_GRAPHICS_BIT) & ~VK_PIPELINE_STAGE_HOST_BIT;
96 }
97 return expanded;
98}
99
John Zulauf36bcf6a2020-02-03 15:12:52 -0700100VkPipelineStageFlags RelatedPipelineStages(VkPipelineStageFlags stage_mask,
101 std::map<VkPipelineStageFlagBits, VkPipelineStageFlags> &map) {
102 VkPipelineStageFlags unscanned = stage_mask;
103 VkPipelineStageFlags related = 0;
104 for (const auto entry : map) {
105 const auto stage = entry.first;
106 if (stage & unscanned) {
107 related = related | entry.second;
108 unscanned = unscanned & ~stage;
109 if (!unscanned) break;
110 }
111 }
112 return related;
113}
114
115VkPipelineStageFlags WithEarlierPipelineStages(VkPipelineStageFlags stage_mask) {
116 return stage_mask | RelatedPipelineStages(stage_mask, syncLogicallyEarlierStages);
117}
118
119VkPipelineStageFlags WithLaterPipelineStages(VkPipelineStageFlags stage_mask) {
120 return stage_mask | RelatedPipelineStages(stage_mask, syncLogicallyLaterStages);
121}
122
John Zulauf5c5e88d2019-12-26 11:22:02 -0700123static const ResourceAccessRange full_range(std::numeric_limits<VkDeviceSize>::min(), std::numeric_limits<VkDeviceSize>::max());
124static ResourceAccessRange MakeMemoryAccessRange(const BUFFER_STATE &buffer, VkDeviceSize offset, VkDeviceSize size) {
John Zulauf9cb530d2019-09-30 14:14:10 -0600125 assert(!buffer.sparse);
126 const auto base = offset + buffer.binding.offset;
John Zulauf5c5e88d2019-12-26 11:22:02 -0700127 return ResourceAccessRange(base, base + size);
128}
129
John Zulauf3d84f1b2020-03-09 13:33:25 -0600130AccessTrackerContext::AccessTrackerContext(uint32_t subpass, VkQueueFlags queue_flags,
131 const std::vector<SubpassDependencyGraphNode> &dependencies,
132 const std::vector<AccessTrackerContext> &contexts,
133 AccessTrackerContext *external_context) {
134 Reset();
135 const auto &subpass_dep = dependencies[subpass];
136 prev_.reserve(subpass_dep.prev.size());
137 for (const auto &prev_dep : subpass_dep.prev) {
138 assert(prev_dep.dependency);
139 const auto dep = *prev_dep.dependency;
140 prev_.emplace_back(const_cast<AccessTrackerContext *>(&contexts[dep.srcSubpass]), queue_flags, dep);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700141 }
John Zulauf3d84f1b2020-03-09 13:33:25 -0600142
143 async_.reserve(subpass_dep.async.size());
144 for (const auto async_subpass : subpass_dep.async) {
145 async_.emplace_back(const_cast<AccessTrackerContext *>(&contexts[async_subpass]));
146 }
147 if (subpass_dep.barrier_from_external)
148 external_ = TrackBack(external_context, queue_flags, *subpass_dep.barrier_from_external);
149 else {
150 external_ = TrackBack();
151 }
John Zulauf5c5e88d2019-12-26 11:22:02 -0700152}
153
John Zulauf3d84f1b2020-03-09 13:33:25 -0600154// A recursive range walker for hazard detection, first for the current context and the (DetectHazardRecur) to walk
155// the DAG of the contexts (for example subpasses)
156template <typename Detector>
157HazardResult AccessTrackerContext::DetectHazard(const VulkanTypedHandle &handle, const Detector &detector,
158 const ResourceAccessRange &range, SyncBarrierStack *barrier_stack) const {
159 const auto access_tracker = GetAccessTracker(handle);
160 bool whole_range_gap = true;
161 HazardResult hazard;
162 if (access_tracker) {
163 const auto &accesses = access_tracker->GetCurrentAccessMap();
164 const auto from = accesses.lower_bound(range);
165 if (from != accesses.end() && from->first.intersects(range)) {
166 whole_range_gap = false;
167 const auto to = accesses.upper_bound(range);
168 ResourceAccessRange gap = {range.begin, range.begin};
169 for (auto pos = from; pos != to; ++pos) {
170 hazard = detector.Detect(pos, barrier_stack);
171 if (hazard.hazard) return hazard;
172
173 // Check for short circuiting recursion over pos->first
174 // If we've just checked against a write we don't have to looke any further...
175 // however even if the current usage is write and there is not hazard with a stored read, we still have to
176 // recur to ensure it's safe against *all* prior/parallel accesses.
177 auto upper_bound = std::min(range.end, pos->first.end);
178 if (detector.ShortCircuit(pos, barrier_stack)) {
179 gap.end = pos->first.begin;
180 } else {
181 // make sure we don't go past range
182 gap.end = upper_bound;
183 }
184 if (!gap.empty()) {
185 // Must recur on all gaps
186 hazard = DetectHazardRecur(handle, detector, gap, barrier_stack);
187 if (hazard.hazard) return hazard;
188 }
189 gap.begin = upper_bound;
190 }
191 }
192 }
193
194 if (whole_range_gap) { // There's no accesses recorded for this range for this context and resource
195 hazard = DetectHazardRecur(handle, detector, range, barrier_stack);
196 }
197 // We only check the async list for top level contexts (empty stack)
198 // Async check are not done at recursive levels, as the async lists are exhaustive for the top-level context
199 if (barrier_stack->size() == 0) {
200 for (const auto &async_context : async_) {
201 hazard = async_context->DetectAsyncHazard(handle, detector, range);
202 if (hazard.hazard) return hazard;
203 }
204 }
205
206 return hazard;
207}
208
209// A non recursive range walker for the asynchronous contexts (those we have no barriers with)
210template <typename Detector>
211HazardResult AccessTrackerContext::DetectAsyncHazard(const VulkanTypedHandle &handle, const Detector &detector,
212 const ResourceAccessRange &range) const {
213 const auto access_tracker = GetAccessTracker(handle);
214 HazardResult hazard;
215 if (access_tracker) {
216 auto accesses = access_tracker->GetCurrentAccessMap();
217 const auto from = accesses.lower_bound(range);
218 const auto to = accesses.upper_bound(range);
219 for (auto pos = from; pos != to; ++pos) {
220 hazard = detector.DetectAsync(pos);
221 if (hazard.hazard) break;
222 }
223 }
224 return hazard;
225}
226
227// Walk the contents or the context's predecessors, checking for hazards invoking the recursive and non-recursive range walkers
228// as appropriate for the type of predecessor
229template <typename Detector>
230HazardResult AccessTrackerContext::DetectHazardRecur(const VulkanTypedHandle &handle, const Detector &detector,
231 const ResourceAccessRange &range, SyncBarrierStack *barrier_stack) const {
232 HazardResult hazard;
233
234 assert(barrier_stack); // Barrier stack is a pointer only by convention (non-const objects to be passed by pointer)
235 for (const auto &prev_dep : prev_) {
236 barrier_stack->push_back(&prev_dep.barrier);
237 hazard = prev_dep.context->DetectHazard(handle, detector, range, barrier_stack);
238 barrier_stack->pop_back();
239 if (hazard.hazard) return hazard;
240 }
241 if (external_.context) {
242 barrier_stack->push_back(&external_.barrier);
243 hazard = external_.context->DetectHazard(handle, detector, range, barrier_stack);
244 barrier_stack->pop_back();
245 if (hazard.hazard) return hazard;
246 }
247
248 return hazard;
249}
250
251template <typename Detector>
252HazardResult AccessTrackerContext::DetectHazard(const VulkanTypedHandle &handle, const Detector &detector,
253 const ResourceAccessRange &range) const {
254 SyncBarrierStack barrier_stack;
255 return DetectHazard(handle, detector, range, &barrier_stack);
256}
257
258class HazardDetector {
259 SyncStageAccessIndex usage_index_;
260
261 public:
262 HazardResult Detect(const ResourceAccessRangeMap::const_iterator &pos, SyncBarrierStack *barrier_stack) const {
263 return pos->second.DetectHazard(usage_index_, barrier_stack);
264 }
265 bool ShortCircuit(const ResourceAccessRangeMap::const_iterator &pos, SyncBarrierStack *barrier_stack) const {
266 // Check for short circuiting recursion over pos->first
267 // If we've just checked against a write we don't have to looke any further...
268 // however even if the current usage is write and there is not hazard with a stored read, we still have to
269 // recur to ensure it's safe against *all* prior/parallel accesses.
270 return pos->second.HasWriteOp();
271 }
272 HazardResult DetectAsync(const ResourceAccessRangeMap::const_iterator &pos) const {
273 return pos->second.DetectAsyncHazard(usage_index_);
274 }
275 HazardDetector(SyncStageAccessIndex usage) : usage_index_(usage) {}
276};
277
278HazardResult AccessTrackerContext::DetectHazard(const VulkanTypedHandle &handle, SyncStageAccessIndex usage_index,
279 const ResourceAccessRange &range) const {
280 HazardDetector detector(usage_index);
281 return DetectHazard(handle, detector, range);
282}
283
284void CommandBufferAccessContext::BeginRenderPass(const RENDER_PASS_STATE &rp_state) {
285 // Create an access context for the first subpass and add it to the command buffers collection
286 render_pass_contexts_.emplace_back(queue_flags_, &rp_state.subpass_dependencies, &cb_tracker_context_);
287 current_renderpass_context_ = &render_pass_contexts_.back();
288 current_context_ = &current_renderpass_context_->CurrentContext();
289}
290
291void CommandBufferAccessContext::NextRenderPass(const RENDER_PASS_STATE &rp_state) {
292 assert(current_renderpass_context_);
293 current_renderpass_context_->NextSubpass(queue_flags_, &cb_tracker_context_);
294 current_context_ = &current_renderpass_context_->CurrentContext();
295}
296
297HazardResult AccessTrackerContext::DetectHazard(const IMAGE_STATE &image, SyncStageAccessIndex current_usage,
298 const VkImageSubresourceLayers &subresource, const VkOffset3D &offset,
299 const VkExtent3D &extent) const {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700300 // TODO: replace the encoder/generator with offset3D/extent3D aware versions
301 VkImageSubresourceRange subresource_range = {subresource.aspectMask, subresource.mipLevel, 1, subresource.baseArrayLayer,
302 subresource.layerCount};
locke-lunarg1dbbb9e2020-02-28 22:43:53 -0700303 VkExtent3D subresource_extent = GetImageSubresourceExtent(&image, &subresource);
304 subresource_adapter::OffsetRangeEncoder encoder(image.full_range, subresource_extent);
305 subresource_adapter::OffsetRangeGenerator range_gen(encoder, subresource_range, offset, extent);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600306 VulkanTypedHandle image_handle(image.image, kVulkanObjectTypeImage);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700307 for (; range_gen->non_empty(); ++range_gen) {
John Zulauf3d84f1b2020-03-09 13:33:25 -0600308 HazardResult hazard = DetectHazard(image_handle, current_usage, *range_gen);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700309 if (hazard.hazard) return hazard;
310 }
311 return HazardResult();
John Zulauf9cb530d2019-09-30 14:14:10 -0600312}
313
John Zulauf3d84f1b2020-03-09 13:33:25 -0600314class BarrierHazardDetector {
315 public:
316 BarrierHazardDetector(SyncStageAccessIndex usage_index, VkPipelineStageFlags src_exec_scope,
317 SyncStageAccessFlags src_access_scope)
318 : usage_index_(usage_index), src_exec_scope_(src_exec_scope), src_access_scope_(src_access_scope) {}
319
320 HazardResult Detect(const ResourceAccessRangeMap::const_iterator &pos, SyncBarrierStack *barrier_stack) const {
321 return pos->second.DetectBarrierHazard(usage_index_, src_exec_scope_, src_access_scope_, barrier_stack);
John Zulauf0cb5be22020-01-23 12:18:22 -0700322 }
John Zulauf3d84f1b2020-03-09 13:33:25 -0600323 bool ShortCircuit(const ResourceAccessRangeMap::const_iterator &pos, SyncBarrierStack *barrier_stack) const { return false; }
324 HazardResult DetectAsync(const ResourceAccessRangeMap::const_iterator &pos) const {
325 // Async barrier hazard detection can use the same path as the usage index is not IsRead, but is IsWrite
326 return pos->second.DetectAsyncHazard(usage_index_);
327 }
328
329 private:
330 SyncStageAccessIndex usage_index_;
331 VkPipelineStageFlags src_exec_scope_;
332 SyncStageAccessFlags src_access_scope_;
333};
334
335HazardResult AccessTrackerContext::DetectBarrierHazard(const VulkanTypedHandle &handle, SyncStageAccessIndex current_usage,
336 VkPipelineStageFlags src_exec_scope, SyncStageAccessFlags src_access_scope,
337 const ResourceAccessRange &range) const {
338 BarrierHazardDetector detector(current_usage, src_exec_scope, src_access_scope);
339 return DetectHazard(handle, detector, range);
John Zulauf0cb5be22020-01-23 12:18:22 -0700340}
341
John Zulauf3d84f1b2020-03-09 13:33:25 -0600342HazardResult DetectImageBarrierHazard(const AccessTrackerContext &context, const IMAGE_STATE &image,
John Zulauf36bcf6a2020-02-03 15:12:52 -0700343 VkPipelineStageFlags src_exec_scope, SyncStageAccessFlags src_stage_accesses,
John Zulauf0cb5be22020-01-23 12:18:22 -0700344 const VkImageMemoryBarrier &barrier) {
John Zulauf0cb5be22020-01-23 12:18:22 -0700345 auto subresource_range = NormalizeSubresourceRange(image.createInfo, barrier.subresourceRange);
locke-lunarg1dbbb9e2020-02-28 22:43:53 -0700346 VkImageSubresourceLayers subresource_layers = {subresource_range.aspectMask, 0, subresource_range.baseArrayLayer,
347 subresource_range.layerCount};
John Zulauf3d84f1b2020-03-09 13:33:25 -0600348 const VulkanTypedHandle image_handle(image.image, kVulkanObjectTypeImage);
John Zulauf36bcf6a2020-02-03 15:12:52 -0700349 const auto src_access_scope = SyncStageAccess::AccessScope(src_stage_accesses, barrier.srcAccessMask);
locke-lunarg1dbbb9e2020-02-28 22:43:53 -0700350 for (uint32_t mip_index = subresource_range.baseMipLevel; mip_index < subresource_range.levelCount; mip_index++) {
351 subresource_layers.mipLevel = mip_index;
352 VkExtent3D subresource_extent = GetImageSubresourceExtent(&image, &subresource_layers);
353 subresource_adapter::OffsetRangeEncoder encoder(image.full_range, subresource_extent);
354 subresource_adapter::OffsetRangeGenerator range_gen(encoder, subresource_range, {0, 0}, subresource_extent);
355 for (; range_gen->non_empty(); ++range_gen) {
356 HazardResult hazard = context.DetectBarrierHazard(image_handle, SyncStageAccessIndex::SYNC_IMAGE_LAYOUT_TRANSITION,
357 src_exec_scope, src_access_scope, *range_gen);
358 if (hazard.hazard) return hazard;
359 }
John Zulauf0cb5be22020-01-23 12:18:22 -0700360 }
361 return HazardResult();
362}
363
John Zulauf9cb530d2019-09-30 14:14:10 -0600364template <typename Flags, typename Map>
365SyncStageAccessFlags AccessScopeImpl(Flags flag_mask, const Map &map) {
366 SyncStageAccessFlags scope = 0;
367 for (const auto &bit_scope : map) {
368 if (flag_mask < bit_scope.first) break;
369
370 if (flag_mask & bit_scope.first) {
371 scope |= bit_scope.second;
372 }
373 }
374 return scope;
375}
376
377SyncStageAccessFlags SyncStageAccess::AccessScopeByStage(VkPipelineStageFlags stages) {
378 return AccessScopeImpl(stages, syncStageAccessMaskByStageBit);
379}
380
381SyncStageAccessFlags SyncStageAccess::AccessScopeByAccess(VkAccessFlags accesses) {
382 return AccessScopeImpl(accesses, syncStageAccessMaskByAccessBit);
383}
384
385// Getting from stage mask and access mask to stage/acess masks is something we need to be good at...
386SyncStageAccessFlags SyncStageAccess::AccessScope(VkPipelineStageFlags stages, VkAccessFlags accesses) {
387 // The access scope is the intersection of all stage/access types possible for the enabled stages and the enables accesses
388 // (after doing a couple factoring of common terms the union of stage/access intersections is the intersections of the
389 // union of all stage/access types for all the stages and the same unions for the access mask...
390 return AccessScopeByStage(stages) & AccessScopeByAccess(accesses);
391}
392
393template <typename Action>
John Zulauf5c5e88d2019-12-26 11:22:02 -0700394void UpdateMemoryAccessState(ResourceAccessRangeMap *accesses, const ResourceAccessRange &range, const Action &action) {
John Zulauf9cb530d2019-09-30 14:14:10 -0600395 // TODO -- region/mem-range accuracte update
396 auto pos = accesses->lower_bound(range);
397 if (pos == accesses->end() || !pos->first.intersects(range)) {
398 // The range is empty, fill it with a default value.
399 pos = action.Infill(accesses, pos, range);
400 } else if (range.begin < pos->first.begin) {
401 // Leading empty space, infill
John Zulauf5c5e88d2019-12-26 11:22:02 -0700402 pos = action.Infill(accesses, pos, ResourceAccessRange(range.begin, pos->first.begin));
John Zulauf9cb530d2019-09-30 14:14:10 -0600403 } else if (pos->first.begin < range.begin) {
404 // Trim the beginning if needed
405 pos = accesses->split(pos, range.begin, sparse_container::split_op_keep_both());
406 ++pos;
407 }
408
409 const auto the_end = accesses->end();
410 while ((pos != the_end) && pos->first.intersects(range)) {
411 if (pos->first.end > range.end) {
412 pos = accesses->split(pos, range.end, sparse_container::split_op_keep_both());
413 }
414
415 pos = action(accesses, pos);
416 if (pos == the_end) break;
417
418 auto next = pos;
419 ++next;
420 if ((pos->first.end < range.end) && (next != the_end) && !next->first.is_subsequent_to(pos->first)) {
421 // Need to infill if next is disjoint
422 VkDeviceSize limit = (next == the_end) ? range.end : std::min(range.end, next->first.begin);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700423 ResourceAccessRange new_range(pos->first.end, limit);
John Zulauf9cb530d2019-09-30 14:14:10 -0600424 next = action.Infill(accesses, next, new_range);
425 }
426 pos = next;
427 }
428}
429
430struct UpdateMemoryAccessStateFunctor {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700431 using Iterator = ResourceAccessRangeMap::iterator;
432 Iterator Infill(ResourceAccessRangeMap *accesses, Iterator pos, ResourceAccessRange range) const {
John Zulauf9cb530d2019-09-30 14:14:10 -0600433 return accesses->insert(pos, std::make_pair(range, ResourceAccessState()));
434 }
John Zulauf5c5e88d2019-12-26 11:22:02 -0700435 Iterator operator()(ResourceAccessRangeMap *accesses, Iterator pos) const {
John Zulauf9cb530d2019-09-30 14:14:10 -0600436 auto &access_state = pos->second;
437 access_state.Update(usage, tag);
438 return pos;
439 }
440
441 UpdateMemoryAccessStateFunctor(SyncStageAccessIndex usage_, const ResourceUsageTag &tag_) : usage(usage_), tag(tag_) {}
442 SyncStageAccessIndex usage;
443 const ResourceUsageTag &tag;
444};
445
446struct ApplyMemoryAccessBarrierFunctor {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700447 using Iterator = ResourceAccessRangeMap::iterator;
448 inline Iterator Infill(ResourceAccessRangeMap *accesses, Iterator pos, ResourceAccessRange range) const { return pos; }
John Zulauf9cb530d2019-09-30 14:14:10 -0600449
John Zulauf5c5e88d2019-12-26 11:22:02 -0700450 Iterator operator()(ResourceAccessRangeMap *accesses, Iterator pos) const {
John Zulauf9cb530d2019-09-30 14:14:10 -0600451 auto &access_state = pos->second;
John Zulauf36bcf6a2020-02-03 15:12:52 -0700452 access_state.ApplyMemoryAccessBarrier(src_exec_scope, src_access_scope, dst_exec_scope, dst_access_scope);
John Zulauf9cb530d2019-09-30 14:14:10 -0600453 return pos;
454 }
455
John Zulauf36bcf6a2020-02-03 15:12:52 -0700456 ApplyMemoryAccessBarrierFunctor(VkPipelineStageFlags src_exec_scope_, SyncStageAccessFlags src_access_scope_,
457 VkPipelineStageFlags dst_exec_scope_, SyncStageAccessFlags dst_access_scope_)
458 : src_exec_scope(src_exec_scope_),
459 src_access_scope(src_access_scope_),
460 dst_exec_scope(dst_exec_scope_),
461 dst_access_scope(dst_access_scope_) {}
John Zulauf9cb530d2019-09-30 14:14:10 -0600462
John Zulauf36bcf6a2020-02-03 15:12:52 -0700463 VkPipelineStageFlags src_exec_scope;
464 SyncStageAccessFlags src_access_scope;
465 VkPipelineStageFlags dst_exec_scope;
466 SyncStageAccessFlags dst_access_scope;
John Zulauf9cb530d2019-09-30 14:14:10 -0600467};
468
469struct ApplyGlobalBarrierFunctor {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700470 using Iterator = ResourceAccessRangeMap::iterator;
471 inline Iterator Infill(ResourceAccessRangeMap *accesses, Iterator pos, ResourceAccessRange range) const { return pos; }
John Zulauf9cb530d2019-09-30 14:14:10 -0600472
John Zulauf5c5e88d2019-12-26 11:22:02 -0700473 Iterator operator()(ResourceAccessRangeMap *accesses, Iterator pos) const {
John Zulauf9cb530d2019-09-30 14:14:10 -0600474 auto &access_state = pos->second;
John Zulauf36bcf6a2020-02-03 15:12:52 -0700475 access_state.ApplyExecutionBarrier(src_exec_scope, dst_exec_scope);
John Zulauf9cb530d2019-09-30 14:14:10 -0600476
477 for (const auto &functor : barrier_functor) {
478 functor(accesses, pos);
479 }
480 return pos;
481 }
482
John Zulauf36bcf6a2020-02-03 15:12:52 -0700483 ApplyGlobalBarrierFunctor(VkPipelineStageFlags src_exec_scope, VkPipelineStageFlags dst_exec_scope,
484 SyncStageAccessFlags src_stage_accesses, SyncStageAccessFlags dst_stage_accesses,
John Zulauf9cb530d2019-09-30 14:14:10 -0600485 uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers)
John Zulauf36bcf6a2020-02-03 15:12:52 -0700486 : src_exec_scope(src_exec_scope), dst_exec_scope(dst_exec_scope) {
John Zulauf9cb530d2019-09-30 14:14:10 -0600487 // Don't want to create this per tracked item, but don't want to loop through all tracked items per barrier...
488 barrier_functor.reserve(memoryBarrierCount);
489 for (uint32_t barrier_index = 0; barrier_index < memoryBarrierCount; barrier_index++) {
490 const auto &barrier = pMemoryBarriers[barrier_index];
John Zulauf36bcf6a2020-02-03 15:12:52 -0700491 barrier_functor.emplace_back(src_exec_scope, SyncStageAccess::AccessScope(src_stage_accesses, barrier.srcAccessMask),
492 dst_exec_scope, SyncStageAccess::AccessScope(dst_stage_accesses, barrier.dstAccessMask));
John Zulauf9cb530d2019-09-30 14:14:10 -0600493 }
494 }
495
John Zulauf36bcf6a2020-02-03 15:12:52 -0700496 const VkPipelineStageFlags src_exec_scope;
497 const VkPipelineStageFlags dst_exec_scope;
John Zulauf9cb530d2019-09-30 14:14:10 -0600498 std::vector<ApplyMemoryAccessBarrierFunctor> barrier_functor;
499};
500
John Zulauf3d84f1b2020-03-09 13:33:25 -0600501void AccessTracker::UpdateAccessState(SyncStageAccessIndex current_usage, const ResourceAccessRange &range,
502 const ResourceUsageTag &tag) {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700503 UpdateMemoryAccessStateFunctor action(current_usage, tag);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600504 UpdateMemoryAccessState(&accesses_, range, action);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700505}
506
John Zulauf3d84f1b2020-03-09 13:33:25 -0600507void AccessTrackerContext::UpdateAccessState(const VulkanTypedHandle &handle, SyncStageAccessIndex current_usage,
508 const ResourceAccessRange &range, const ResourceUsageTag &tag) {
509 auto *tracker = GetAccessTracker(handle);
510 assert(tracker);
511 tracker->UpdateAccessState(current_usage, range, tag);
512}
513
514void AccessTracker::UpdateAccessState(const IMAGE_STATE &image, SyncStageAccessIndex current_usage,
515 const VkImageSubresourceLayers &subresource, const VkOffset3D &offset,
516 const VkExtent3D &extent, const ResourceUsageTag &tag) {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700517 // TODO: replace the encoder/generator with offset3D aware versions
518 VkImageSubresourceRange subresource_range = {subresource.aspectMask, subresource.mipLevel, 1, subresource.baseArrayLayer,
519 subresource.layerCount};
locke-lunarg1dbbb9e2020-02-28 22:43:53 -0700520 VkExtent3D subresource_extent = GetImageSubresourceExtent(&image, &subresource);
521 subresource_adapter::OffsetRangeEncoder encoder(image.full_range, subresource_extent);
522 subresource_adapter::OffsetRangeGenerator range_gen(encoder, subresource_range, offset, extent);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700523 for (; range_gen->non_empty(); ++range_gen) {
John Zulauf3d84f1b2020-03-09 13:33:25 -0600524 UpdateAccessState(current_usage, *range_gen, tag);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700525 }
526}
527
John Zulauf3d84f1b2020-03-09 13:33:25 -0600528void AccessTrackerContext::UpdateAccessState(const IMAGE_STATE &image, SyncStageAccessIndex current_usage,
529 const VkImageSubresourceLayers &subresource, const VkOffset3D &offset,
530 const VkExtent3D &extent, const ResourceUsageTag &tag) {
531 const VulkanTypedHandle handle(image.image, kVulkanObjectTypeImage);
532 auto *tracker = GetAccessTracker(handle);
533 assert(tracker);
534 tracker->UpdateAccessState(image, current_usage, subresource, offset, extent, tag);
535}
536
537SyncBarrier::SyncBarrier(VkQueueFlags queue_flags, const VkSubpassDependency2 &barrier) {
538 const auto src_stage_mask = ExpandPipelineStages(queue_flags, barrier.srcStageMask);
539 src_exec_scope = WithEarlierPipelineStages(src_stage_mask);
540 src_access_scope = SyncStageAccess::AccessScope(src_stage_mask, barrier.srcAccessMask);
541 const auto dst_stage_mask = ExpandPipelineStages(queue_flags, barrier.dstStageMask);
542 dst_exec_scope = WithLaterPipelineStages(dst_stage_mask);
543 dst_access_scope = SyncStageAccess::AccessScope(dst_stage_mask, barrier.dstAccessMask);
544}
545
546void ResourceAccessState::ApplyBarrier(const SyncBarrier &barrier) {
547 ApplyExecutionBarrier(barrier.src_exec_scope, barrier.dst_exec_scope);
548 ApplyMemoryAccessBarrier(barrier.src_exec_scope, barrier.src_access_scope, barrier.dst_exec_scope, barrier.dst_access_scope);
549}
550
551ResourceAccessState ResourceAccessState::ApplyBarrierStack(const ResourceAccessState &that, const SyncBarrierStack &barrier_stack) {
552 ResourceAccessState copy = that;
553 for (auto barrier = barrier_stack.begin(); barrier != barrier_stack.end(); ++barrier) {
554 assert(*barrier);
555 copy.ApplyBarrier(*(*barrier));
556 }
557 return copy;
558}
559
560HazardResult ResourceAccessState::DetectHazard(SyncStageAccessIndex usage_index, SyncBarrierStack *barrier_stack) const {
561 if (barrier_stack) {
562 return ApplyBarrierStack(*this, *barrier_stack).DetectHazard(usage_index);
563 }
564 return DetectHazard(usage_index);
565}
566
John Zulauf9cb530d2019-09-30 14:14:10 -0600567HazardResult ResourceAccessState::DetectHazard(SyncStageAccessIndex usage_index) const {
568 HazardResult hazard;
569 auto usage = FlagBit(usage_index);
570 if (IsRead(usage)) {
571 if (IsWriteHazard(usage)) {
572 hazard.Set(READ_AFTER_WRITE, write_tag);
573 }
574 } else {
575 // Assume write
576 // TODO determine what to do with READ-WRITE usage states if any
577 // Write-After-Write check -- if we have a previous write to test against
578 if (last_write && IsWriteHazard(usage)) {
579 hazard.Set(WRITE_AFTER_WRITE, write_tag);
580 } else {
581 // Only look for casus belli for WAR
582 const auto usage_stage = PipelineStageBit(usage_index);
583 for (uint32_t read_index = 0; read_index < last_read_count; read_index++) {
584 if (IsReadHazard(usage_stage, last_reads[read_index])) {
585 hazard.Set(WRITE_AFTER_READ, last_reads[read_index].tag);
586 break;
587 }
588 }
589 }
590 }
591 return hazard;
592}
593
John Zulauf2f952d22020-02-10 11:34:51 -0700594// Asynchronous Hazards occur between subpasses with no connection through the DAG
John Zulauf3d84f1b2020-03-09 13:33:25 -0600595HazardResult ResourceAccessState::DetectAsyncHazard(SyncStageAccessIndex usage_index) const {
John Zulauf2f952d22020-02-10 11:34:51 -0700596 HazardResult hazard;
597 auto usage = FlagBit(usage_index);
598 if (IsRead(usage)) {
599 if (last_write != 0) {
600 hazard.Set(READ_RACING_WRITE, write_tag);
601 }
602 } else {
603 if (last_write != 0) {
604 hazard.Set(WRITE_RACING_WRITE, write_tag);
605 } else if (last_read_count > 0) {
606 hazard.Set(WRITE_RACING_READ, last_reads[0].tag);
607 }
608 }
609 return hazard;
610}
611
John Zulauf36bcf6a2020-02-03 15:12:52 -0700612HazardResult ResourceAccessState::DetectBarrierHazard(SyncStageAccessIndex usage_index, VkPipelineStageFlags src_exec_scope,
John Zulauf3d84f1b2020-03-09 13:33:25 -0600613 SyncStageAccessFlags src_access_scope,
614 SyncBarrierStack *barrier_stack) const {
615 if (barrier_stack) {
616 return ApplyBarrierStack(*this, *barrier_stack).DetectBarrierHazard(usage_index, src_exec_scope, src_access_scope);
617 }
618 return DetectBarrierHazard(usage_index, src_exec_scope, src_access_scope);
619}
620
621HazardResult ResourceAccessState::DetectBarrierHazard(SyncStageAccessIndex usage_index, VkPipelineStageFlags src_exec_scope,
John Zulauf36bcf6a2020-02-03 15:12:52 -0700622 SyncStageAccessFlags src_access_scope) const {
John Zulauf0cb5be22020-01-23 12:18:22 -0700623 // Only supporting image layout transitions for now
624 assert(usage_index == SyncStageAccessIndex::SYNC_IMAGE_LAYOUT_TRANSITION);
625 HazardResult hazard;
626 if (last_write) {
627 // If the previous write is *not* in the 1st access scope
628 // *AND* the current barrier is not in the dependency chain
629 // *AND* the there is no prior memory barrier for the previous write in the dependency chain
630 // then the barrier access is unsafe (R/W after W)
John Zulauf36bcf6a2020-02-03 15:12:52 -0700631 if (((last_write & src_access_scope) == 0) && ((src_exec_scope & write_dependency_chain) == 0) && (write_barriers == 0)) {
John Zulauf0cb5be22020-01-23 12:18:22 -0700632 // TODO: Do we need a difference hazard name for this?
633 hazard.Set(WRITE_AFTER_WRITE, write_tag);
634 }
635 } else {
636 // Look at the reads
637 for (uint32_t read_index = 0; read_index < last_read_count; read_index++) {
John Zulauf36bcf6a2020-02-03 15:12:52 -0700638 const auto &read_access = last_reads[read_index];
639 // If the read stage is not in the src sync sync
640 // *AND* not execution chained with an existing sync barrier (that's the or)
641 // then the barrier access is unsafe (R/W after R)
642 if ((src_exec_scope & (read_access.stage | read_access.barriers)) == 0) {
643 hazard.Set(WRITE_AFTER_READ, read_access.tag);
John Zulauf0cb5be22020-01-23 12:18:22 -0700644 break;
645 }
646 }
647 }
648 return hazard;
649}
650
John Zulauf9cb530d2019-09-30 14:14:10 -0600651void ResourceAccessState::Update(SyncStageAccessIndex usage_index, const ResourceUsageTag &tag) {
652 // Move this logic in the ResourceStateTracker as methods, thereof (or we'll repeat it for every flavor of resource...
653 const auto usage_bit = FlagBit(usage_index);
654 if (IsRead(usage_index)) {
655 // Mulitple outstanding reads may be of interest and do dependency chains independently
656 // However, for purposes of barrier tracking, only one read per pipeline stage matters
657 const auto usage_stage = PipelineStageBit(usage_index);
658 if (usage_stage & last_read_stages) {
659 for (uint32_t read_index = 0; read_index < last_read_count; read_index++) {
660 ReadState &access = last_reads[read_index];
661 if (access.stage == usage_stage) {
662 access.barriers = 0;
663 access.tag = tag;
664 break;
665 }
666 }
667 } else {
668 // We don't have this stage in the list yet...
669 assert(last_read_count < last_reads.size());
670 ReadState &access = last_reads[last_read_count++];
671 access.stage = usage_stage;
672 access.barriers = 0;
673 access.tag = tag;
674 last_read_stages |= usage_stage;
675 }
676 } else {
677 // Assume write
678 // TODO determine what to do with READ-WRITE operations if any
679 // Clobber last read and both sets of barriers... because all we have is DANGER, DANGER, WILL ROBINSON!!!
680 // if the last_reads/last_write were unsafe, we've reported them,
681 // in either case the prior access is irrelevant, we can overwrite them as *this* write is now after them
682 last_read_count = 0;
683 last_read_stages = 0;
684
685 write_barriers = 0;
686 write_dependency_chain = 0;
687 write_tag = tag;
688 last_write = usage_bit;
689 }
690}
691void ResourceAccessState::ApplyExecutionBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask) {
692 // Execution Barriers only protect read operations
693 for (uint32_t read_index = 0; read_index < last_read_count; read_index++) {
694 ReadState &access = last_reads[read_index];
695 // The | implements the "dependency chain" logic for this access, as the barriers field stores the second sync scope
696 if (srcStageMask & (access.stage | access.barriers)) {
697 access.barriers |= dstStageMask;
698 }
699 }
700 if (write_dependency_chain & srcStageMask) write_dependency_chain |= dstStageMask;
701}
702
John Zulauf36bcf6a2020-02-03 15:12:52 -0700703void ResourceAccessState::ApplyMemoryAccessBarrier(VkPipelineStageFlags src_exec_scope, SyncStageAccessFlags src_access_scope,
704 VkPipelineStageFlags dst_exec_scope, SyncStageAccessFlags dst_access_scope) {
John Zulauf9cb530d2019-09-30 14:14:10 -0600705 // Assuming we've applied the execution side of this barrier, we update just the write
706 // The || implements the "dependency chain" logic for this barrier
John Zulauf36bcf6a2020-02-03 15:12:52 -0700707 if ((src_access_scope & last_write) || (write_dependency_chain & src_exec_scope)) {
708 write_barriers |= dst_access_scope;
709 write_dependency_chain |= dst_exec_scope;
John Zulauf9cb530d2019-09-30 14:14:10 -0600710 }
711}
712
713void SyncValidator::ResetCommandBuffer(VkCommandBuffer command_buffer) {
John Zulauf3d84f1b2020-03-09 13:33:25 -0600714 auto *access_context = GetAccessContextNoInsert(command_buffer);
715 if (access_context) {
716 access_context->Reset();
John Zulauf9cb530d2019-09-30 14:14:10 -0600717 }
718}
719
John Zulauf3d84f1b2020-03-09 13:33:25 -0600720void SyncValidator::ApplyGlobalBarriers(AccessTrackerContext *context, VkPipelineStageFlags srcStageMask,
John Zulauf36bcf6a2020-02-03 15:12:52 -0700721 VkPipelineStageFlags dstStageMask, SyncStageAccessFlags src_access_scope,
722 SyncStageAccessFlags dst_access_scope, uint32_t memoryBarrierCount,
John Zulauf9cb530d2019-09-30 14:14:10 -0600723 const VkMemoryBarrier *pMemoryBarriers) {
724 // TODO: Implement this better (maybe some delayed/on-demand integration).
John Zulauf36bcf6a2020-02-03 15:12:52 -0700725 ApplyGlobalBarrierFunctor barriers_functor(srcStageMask, dstStageMask, src_access_scope, dst_access_scope, memoryBarrierCount,
John Zulauf9cb530d2019-09-30 14:14:10 -0600726 pMemoryBarriers);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600727 for (auto &handle_tracker_pair : context->GetAccessTrackerMap()) {
728 UpdateMemoryAccessState(&handle_tracker_pair.second.GetCurrentAccessMap(), full_range, barriers_functor);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700729 }
John Zulauf9cb530d2019-09-30 14:14:10 -0600730}
731
John Zulauf3d84f1b2020-03-09 13:33:25 -0600732void SyncValidator::ApplyBufferBarriers(AccessTrackerContext *context, VkPipelineStageFlags src_exec_scope,
John Zulauf36bcf6a2020-02-03 15:12:52 -0700733 SyncStageAccessFlags src_stage_accesses, VkPipelineStageFlags dst_exec_scope,
734 SyncStageAccessFlags dst_stage_accesses, uint32_t barrier_count,
John Zulauf9cb530d2019-09-30 14:14:10 -0600735 const VkBufferMemoryBarrier *barriers) {
736 // TODO Implement this at subresource/memory_range accuracy
737 for (uint32_t index = 0; index < barrier_count; index++) {
738 const auto &barrier = barriers[index];
739 const auto *buffer = Get<BUFFER_STATE>(barrier.buffer);
740 if (!buffer) continue;
John Zulauf3d84f1b2020-03-09 13:33:25 -0600741 auto *tracker = context->GetAccessTracker(VulkanTypedHandle(buffer->binding.mem_state->mem, kVulkanObjectTypeDeviceMemory));
742 if (!tracker) continue;
John Zulauf5c5e88d2019-12-26 11:22:02 -0700743 ResourceAccessRange range = MakeMemoryAccessRange(*buffer, barrier.offset, barrier.size);
John Zulauf9cb530d2019-09-30 14:14:10 -0600744 UpdateMemoryAccessState(
John Zulauf3d84f1b2020-03-09 13:33:25 -0600745 &tracker->GetCurrentAccessMap(), range,
John Zulauf36bcf6a2020-02-03 15:12:52 -0700746 ApplyMemoryAccessBarrierFunctor(src_exec_scope, AccessScope(src_stage_accesses, barrier.srcAccessMask), dst_exec_scope,
747 AccessScope(dst_stage_accesses, barrier.dstAccessMask)));
John Zulauf9cb530d2019-09-30 14:14:10 -0600748 }
749}
750
John Zulauf3d84f1b2020-03-09 13:33:25 -0600751void SyncValidator::ApplyImageBarriers(AccessTrackerContext *context, VkPipelineStageFlags src_exec_scope,
John Zulauf36bcf6a2020-02-03 15:12:52 -0700752 SyncStageAccessFlags src_stage_accesses, VkPipelineStageFlags dst_exec_scope,
753 SyncStageAccessFlags dst_stage_accesses, uint32_t barrier_count,
John Zulauf5c5e88d2019-12-26 11:22:02 -0700754 const VkImageMemoryBarrier *barriers) {
755 for (uint32_t index = 0; index < barrier_count; index++) {
756 const auto &barrier = barriers[index];
757 const auto *image = Get<IMAGE_STATE>(barrier.image);
758 if (!image) continue;
John Zulauf3d84f1b2020-03-09 13:33:25 -0600759 auto tracker = context->GetAccessTrackerNoInsert(VulkanTypedHandle(barrier.image, kVulkanObjectTypeImage));
760 if (!tracker) continue;
761 auto *accesses = &tracker->GetCurrentAccessMap();
762
John Zulauf5c5e88d2019-12-26 11:22:02 -0700763 auto subresource_range = NormalizeSubresourceRange(image->createInfo, barrier.subresourceRange);
locke-lunarg1dbbb9e2020-02-28 22:43:53 -0700764 VkImageSubresourceLayers subresource_layers = {subresource_range.aspectMask, 0, subresource_range.baseArrayLayer,
765 subresource_range.layerCount};
766 for (uint32_t mip_index = subresource_range.baseMipLevel; mip_index < subresource_range.levelCount; mip_index++) {
767 subresource_layers.mipLevel = mip_index;
768 VkExtent3D subresource_extent = GetImageSubresourceExtent(image, &subresource_layers);
769 subresource_adapter::OffsetRangeEncoder encoder(image->full_range, subresource_extent);
770 subresource_adapter::OffsetRangeGenerator range_gen(encoder, subresource_range, {0, 0}, subresource_extent);
771
772 const ApplyMemoryAccessBarrierFunctor barrier_action(
773 src_exec_scope, AccessScope(src_stage_accesses, barrier.srcAccessMask), dst_exec_scope,
774 AccessScope(dst_stage_accesses, barrier.dstAccessMask));
775 for (; range_gen->non_empty(); ++range_gen) {
776 UpdateMemoryAccessState(accesses, *range_gen, barrier_action);
777 }
John Zulauf5c5e88d2019-12-26 11:22:02 -0700778 }
John Zulauf9cb530d2019-09-30 14:14:10 -0600779 }
John Zulauf9cb530d2019-09-30 14:14:10 -0600780}
781
782bool SyncValidator::PreCallValidateCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
783 uint32_t regionCount, const VkBufferCopy *pRegions) const {
784 bool skip = false;
John Zulauf3d84f1b2020-03-09 13:33:25 -0600785 const auto *cb_context = GetAccessContext(commandBuffer);
786 assert(cb_context);
787 if (!cb_context) return skip;
788 const auto *context = cb_context->GetCurrentAccessContext();
John Zulauf9cb530d2019-09-30 14:14:10 -0600789
John Zulauf3d84f1b2020-03-09 13:33:25 -0600790 // If we have no previous accesses, we have no hazards
791 // TODO: make this sub-resource capable
792 // TODO: make this general, and stuff it into templates/utility functions
793 const auto *src_buffer = Get<BUFFER_STATE>(srcBuffer);
794 const auto src_mem = (src_buffer && !src_buffer->sparse) ? src_buffer->binding.mem_state->mem : VK_NULL_HANDLE;
795 const auto *dst_buffer = Get<BUFFER_STATE>(dstBuffer);
796 const auto dst_mem = (dst_buffer && !dst_buffer->sparse) ? dst_buffer->binding.mem_state->mem : VK_NULL_HANDLE;
797
798 for (uint32_t region = 0; region < regionCount; region++) {
799 const auto &copy_region = pRegions[region];
800 if (src_mem != VK_NULL_HANDLE) {
801 ResourceAccessRange src_range = MakeMemoryAccessRange(*src_buffer, copy_region.srcOffset, copy_region.size);
802 auto hazard = context->DetectHazard(VulkanTypedHandle(src_mem, kVulkanObjectTypeDeviceMemory),
803 SYNC_TRANSFER_TRANSFER_READ, src_range);
804 if (hazard.hazard) {
805 // TODO -- add tag information to log msg when useful.
806 skip |= LogError(srcBuffer, string_SyncHazardVUID(hazard.hazard), "Hazard %s for srcBuffer %s, region %" PRIu32,
807 string_SyncHazard(hazard.hazard), report_data->FormatHandle(srcBuffer).c_str(), region);
John Zulauf9cb530d2019-09-30 14:14:10 -0600808 }
John Zulauf9cb530d2019-09-30 14:14:10 -0600809 }
John Zulauf3d84f1b2020-03-09 13:33:25 -0600810 if ((dst_mem != VK_NULL_HANDLE) && !skip) {
811 ResourceAccessRange dst_range = MakeMemoryAccessRange(*dst_buffer, copy_region.dstOffset, copy_region.size);
812 auto hazard = context->DetectHazard(VulkanTypedHandle(dst_mem, kVulkanObjectTypeDeviceMemory),
813 SYNC_TRANSFER_TRANSFER_WRITE, dst_range);
814 if (hazard.hazard) {
815 skip |= LogError(dstBuffer, string_SyncHazardVUID(hazard.hazard), "Hazard %s for dstBuffer %s, region %" PRIu32,
816 string_SyncHazard(hazard.hazard), report_data->FormatHandle(dstBuffer).c_str(), region);
817 }
818 }
819 if (skip) break;
John Zulauf9cb530d2019-09-30 14:14:10 -0600820 }
821 return skip;
822}
823
824void SyncValidator::PreCallRecordCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
825 uint32_t regionCount, const VkBufferCopy *pRegions) {
John Zulauf3d84f1b2020-03-09 13:33:25 -0600826 auto *cb_context = GetAccessContext(commandBuffer);
827 assert(cb_context);
828 auto *context = cb_context->GetCurrentAccessContext();
829
John Zulauf9cb530d2019-09-30 14:14:10 -0600830 const auto *src_buffer = Get<BUFFER_STATE>(srcBuffer);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600831 const auto src_mem = (src_buffer && !src_buffer->sparse) ? src_buffer->binding.mem_state->mem : VK_NULL_HANDLE;
832 const VulkanTypedHandle src_handle(src_mem, kVulkanObjectTypeDeviceMemory);
833 AccessTracker *src_tracker = src_mem ? context->GetAccessTracker(src_handle) : nullptr;
834
John Zulauf9cb530d2019-09-30 14:14:10 -0600835 const auto *dst_buffer = Get<BUFFER_STATE>(dstBuffer);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600836 const auto dst_mem = (dst_buffer && !dst_buffer->sparse) ? dst_buffer->binding.mem_state->mem : VK_NULL_HANDLE;
837 const VulkanTypedHandle dst_handle(dst_mem, kVulkanObjectTypeDeviceMemory);
838 AccessTracker *dst_tracker = dst_mem ? context->GetAccessTracker(dst_handle) : nullptr;
John Zulauf9cb530d2019-09-30 14:14:10 -0600839
840 for (uint32_t region = 0; region < regionCount; region++) {
841 const auto &copy_region = pRegions[region];
John Zulauf3d84f1b2020-03-09 13:33:25 -0600842 if (src_mem) {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700843 ResourceAccessRange src_range = MakeMemoryAccessRange(*src_buffer, copy_region.srcOffset, copy_region.size);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600844 src_tracker->UpdateAccessState(SYNC_TRANSFER_TRANSFER_READ, src_range, tag);
John Zulauf9cb530d2019-09-30 14:14:10 -0600845 }
John Zulauf3d84f1b2020-03-09 13:33:25 -0600846 if (dst_mem) {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700847 ResourceAccessRange dst_range = MakeMemoryAccessRange(*dst_buffer, copy_region.dstOffset, copy_region.size);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600848 dst_tracker->UpdateAccessState(SYNC_TRANSFER_TRANSFER_WRITE, dst_range, tag);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700849 }
850 }
851}
852
853bool SyncValidator::PreCallValidateCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
854 VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
855 const VkImageCopy *pRegions) const {
856 bool skip = false;
John Zulauf3d84f1b2020-03-09 13:33:25 -0600857 const auto *cb_access_context = GetAccessContext(commandBuffer);
858 assert(cb_access_context);
859 if (!cb_access_context) return skip;
John Zulauf5c5e88d2019-12-26 11:22:02 -0700860
John Zulauf3d84f1b2020-03-09 13:33:25 -0600861 const auto *context = cb_access_context->GetCurrentAccessContext();
862 assert(context);
863 if (!context) return skip;
864
865 const auto *src_image = Get<IMAGE_STATE>(srcImage);
866 const auto *dst_image = Get<IMAGE_STATE>(dstImage);
867
868 for (uint32_t region = 0; region < regionCount; region++) {
869 const auto &copy_region = pRegions[region];
870 if (src_image) {
871 auto hazard = context->DetectHazard(*src_image, SYNC_TRANSFER_TRANSFER_READ, copy_region.srcSubresource,
872 copy_region.srcOffset, copy_region.extent);
873 if (hazard.hazard) {
874 skip |= LogError(srcImage, string_SyncHazardVUID(hazard.hazard), "Hazard %s for srcImage %s, region %" PRIu32,
875 string_SyncHazard(hazard.hazard), report_data->FormatHandle(srcImage).c_str(), region);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700876 }
John Zulauf3d84f1b2020-03-09 13:33:25 -0600877 }
878
879 if (dst_image) {
locke-lunarg1df1f882020-03-02 16:42:08 -0700880 VkExtent3D dst_copy_extent =
881 GetAdjustedDestImageExtent(src_image->createInfo.format, dst_image->createInfo.format, copy_region.extent);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600882 auto hazard = context->DetectHazard(*dst_image, SYNC_TRANSFER_TRANSFER_WRITE, copy_region.dstSubresource,
locke-lunarg1df1f882020-03-02 16:42:08 -0700883 copy_region.dstOffset, dst_copy_extent);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600884 if (hazard.hazard) {
885 skip |= LogError(dstImage, string_SyncHazardVUID(hazard.hazard), "Hazard %s for dstImage %s, region %" PRIu32,
886 string_SyncHazard(hazard.hazard), report_data->FormatHandle(dstImage).c_str(), region);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700887 }
locke-lunarg1dbbb9e2020-02-28 22:43:53 -0700888 if (skip) break;
John Zulauf5c5e88d2019-12-26 11:22:02 -0700889 }
890 }
John Zulauf3d84f1b2020-03-09 13:33:25 -0600891
John Zulauf5c5e88d2019-12-26 11:22:02 -0700892 return skip;
893}
894
895void SyncValidator::PreCallRecordCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
896 VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
897 const VkImageCopy *pRegions) {
John Zulauf3d84f1b2020-03-09 13:33:25 -0600898 auto *cb_access_context = GetAccessContext(commandBuffer);
899 assert(cb_access_context);
900 auto *context = cb_access_context->GetCurrentAccessContext();
901 assert(context);
902
John Zulauf5c5e88d2019-12-26 11:22:02 -0700903 auto *src_image = Get<IMAGE_STATE>(srcImage);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600904 auto *src_tracker = context->GetAccessTracker(VulkanTypedHandle(srcImage, kVulkanObjectTypeImage));
John Zulauf5c5e88d2019-12-26 11:22:02 -0700905 auto *dst_image = Get<IMAGE_STATE>(dstImage);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600906 auto *dst_tracker = context->GetAccessTracker(VulkanTypedHandle(dstImage, kVulkanObjectTypeImage));
John Zulauf5c5e88d2019-12-26 11:22:02 -0700907
908 for (uint32_t region = 0; region < regionCount; region++) {
909 const auto &copy_region = pRegions[region];
John Zulauf3d84f1b2020-03-09 13:33:25 -0600910 if (src_image) {
911 src_tracker->UpdateAccessState(*src_image, SYNC_TRANSFER_TRANSFER_READ, copy_region.srcSubresource,
912 copy_region.srcOffset, copy_region.extent, tag);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700913 }
John Zulauf3d84f1b2020-03-09 13:33:25 -0600914 if (dst_image) {
locke-lunarg1df1f882020-03-02 16:42:08 -0700915 VkExtent3D dst_copy_extent =
916 GetAdjustedDestImageExtent(src_image->createInfo.format, dst_image->createInfo.format, copy_region.extent);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600917 dst_tracker->UpdateAccessState(*dst_image, SYNC_TRANSFER_TRANSFER_WRITE, copy_region.dstSubresource,
locke-lunarg1df1f882020-03-02 16:42:08 -0700918 copy_region.dstOffset, dst_copy_extent, tag);
John Zulauf9cb530d2019-09-30 14:14:10 -0600919 }
920 }
921}
922
923bool SyncValidator::PreCallValidateCmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask,
924 VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags,
925 uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
926 uint32_t bufferMemoryBarrierCount,
927 const VkBufferMemoryBarrier *pBufferMemoryBarriers,
928 uint32_t imageMemoryBarrierCount,
929 const VkImageMemoryBarrier *pImageMemoryBarriers) const {
930 bool skip = false;
John Zulauf3d84f1b2020-03-09 13:33:25 -0600931 const auto *cb_access_context = GetAccessContext(commandBuffer);
932 assert(cb_access_context);
933 if (!cb_access_context) return skip;
John Zulauf0cb5be22020-01-23 12:18:22 -0700934
John Zulauf3d84f1b2020-03-09 13:33:25 -0600935 const auto *context = cb_access_context->GetCurrentAccessContext();
936 assert(context);
937 if (!context) return skip;
John Zulauf0cb5be22020-01-23 12:18:22 -0700938
John Zulauf3d84f1b2020-03-09 13:33:25 -0600939 const auto src_stage_mask = ExpandPipelineStages(cb_access_context->GetQueueFlags(), srcStageMask);
John Zulauf36bcf6a2020-02-03 15:12:52 -0700940 const auto src_exec_scope = WithEarlierPipelineStages(src_stage_mask);
941 auto src_stage_accesses = AccessScopeByStage(src_stage_mask);
John Zulauf0cb5be22020-01-23 12:18:22 -0700942 // Validate Image Layout transitions
943 for (uint32_t index = 0; index < imageMemoryBarrierCount; index++) {
944 const auto &barrier = pImageMemoryBarriers[index];
945 if (barrier.newLayout == barrier.oldLayout) continue; // Only interested in layout transitions at this point.
946 const auto *image_state = Get<IMAGE_STATE>(barrier.image);
947 if (!image_state) continue;
John Zulauf3d84f1b2020-03-09 13:33:25 -0600948 const auto hazard = DetectImageBarrierHazard(*context, *image_state, src_exec_scope, src_stage_accesses, barrier);
John Zulauf0cb5be22020-01-23 12:18:22 -0700949 if (hazard.hazard) {
950 // TODO -- add tag information to log msg when useful.
951 skip |= LogError(barrier.image, string_SyncHazardVUID(hazard.hazard), "Hazard %s for image barrier %" PRIu32 " %s",
952 string_SyncHazard(hazard.hazard), index, report_data->FormatHandle(barrier.image).c_str());
953 }
954 }
John Zulauf9cb530d2019-09-30 14:14:10 -0600955
956 return skip;
957}
958
959void SyncValidator::PreCallRecordCmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask,
960 VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags,
961 uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
962 uint32_t bufferMemoryBarrierCount,
963 const VkBufferMemoryBarrier *pBufferMemoryBarriers,
964 uint32_t imageMemoryBarrierCount,
965 const VkImageMemoryBarrier *pImageMemoryBarriers) {
John Zulauf3d84f1b2020-03-09 13:33:25 -0600966 auto *cb_access_context = GetAccessContext(commandBuffer);
967 assert(cb_access_context);
968 if (!cb_access_context) return;
969 auto access_context = cb_access_context->GetCurrentAccessContext();
970 assert(access_context);
971 if (!access_context) return;
John Zulauf9cb530d2019-09-30 14:14:10 -0600972
John Zulauf3d84f1b2020-03-09 13:33:25 -0600973 const auto src_stage_mask = ExpandPipelineStages(cb_access_context->GetQueueFlags(), srcStageMask);
John Zulauf36bcf6a2020-02-03 15:12:52 -0700974 auto src_stage_accesses = AccessScopeByStage(src_stage_mask);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600975 const auto dst_stage_mask = ExpandPipelineStages(cb_access_context->GetQueueFlags(), dstStageMask);
John Zulauf36bcf6a2020-02-03 15:12:52 -0700976 auto dst_stage_accesses = AccessScopeByStage(dst_stage_mask);
977 const auto src_exec_scope = WithEarlierPipelineStages(src_stage_mask);
978 const auto dst_exec_scope = WithLaterPipelineStages(dst_stage_mask);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600979 ApplyBufferBarriers(access_context, src_exec_scope, src_stage_accesses, dst_exec_scope, dst_stage_accesses,
980 bufferMemoryBarrierCount, pBufferMemoryBarriers);
981 ApplyImageBarriers(access_context, src_exec_scope, src_stage_accesses, dst_exec_scope, dst_stage_accesses,
982 imageMemoryBarrierCount, pImageMemoryBarriers);
John Zulauf9cb530d2019-09-30 14:14:10 -0600983
984 // Apply these last in-case there operation is a superset of the other two and would clean them up...
John Zulauf3d84f1b2020-03-09 13:33:25 -0600985 ApplyGlobalBarriers(access_context, src_exec_scope, dst_exec_scope, src_stage_accesses, dst_stage_accesses, memoryBarrierCount,
John Zulauf0cb5be22020-01-23 12:18:22 -0700986 pMemoryBarriers);
John Zulauf9cb530d2019-09-30 14:14:10 -0600987}
988
989void SyncValidator::PostCallRecordCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo,
990 const VkAllocationCallbacks *pAllocator, VkDevice *pDevice, VkResult result) {
991 // The state tracker sets up the device state
992 StateTracker::PostCallRecordCreateDevice(gpu, pCreateInfo, pAllocator, pDevice, result);
993
994 // Add the callback hooks for the functions that are either broadly or deeply used and that the ValidationStateTracker refactor
995 // would be messier without.
996 // TODO: Find a good way to do this hooklessly.
997 ValidationObject *device_object = GetLayerDataPtr(get_dispatch_key(*pDevice), layer_data_map);
998 ValidationObject *validation_data = GetValidationObject(device_object->object_dispatch, LayerObjectTypeSyncValidation);
999 SyncValidator *sync_device_state = static_cast<SyncValidator *>(validation_data);
1000
1001 sync_device_state->SetCommandBufferResetCallback(
1002 [sync_device_state](VkCommandBuffer command_buffer) -> void { sync_device_state->ResetCommandBuffer(command_buffer); });
1003}
John Zulauf3d84f1b2020-03-09 13:33:25 -06001004
1005void SyncValidator::PostCallRecordBeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo,
1006 VkResult result) {
1007 // The state tracker sets up the command buffer state
1008 StateTracker::PostCallRecordBeginCommandBuffer(commandBuffer, pBeginInfo, result);
1009
1010 // Create/initialize the structure that trackers accesses at the command buffer scope.
1011 auto cb_access_context = GetAccessContext(commandBuffer);
1012 assert(cb_access_context);
1013 cb_access_context->Reset();
1014}
1015
1016void SyncValidator::RecordCmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
1017 const VkSubpassBeginInfo *pSubpassBeginInfo) {
1018 const auto rp_state = Get<RENDER_PASS_STATE>(pRenderPassBegin->renderPass);
1019 auto cb_context = GetAccessContext(commandBuffer);
1020 if (rp_state && cb_context) {
1021 cb_context->BeginRenderPass(*rp_state);
1022 }
1023}
1024
1025void SyncValidator::PostCallRecordCmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
1026 VkSubpassContents contents) {
1027 StateTracker::PostCallRecordCmdBeginRenderPass(commandBuffer, pRenderPassBegin, contents);
1028 auto subpass_begin_info = lvl_init_struct<VkSubpassBeginInfo>();
1029 subpass_begin_info.contents = contents;
1030 RecordCmdBeginRenderPass(commandBuffer, pRenderPassBegin, &subpass_begin_info);
1031}
1032
1033void SyncValidator::PostCallRecordCmdBeginRenderPass2(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
1034 const VkSubpassBeginInfo *pSubpassBeginInfo) {
1035 StateTracker::PostCallRecordCmdBeginRenderPass2(commandBuffer, pRenderPassBegin, pSubpassBeginInfo);
1036 RecordCmdBeginRenderPass(commandBuffer, pRenderPassBegin, pSubpassBeginInfo);
1037}
1038
1039void SyncValidator::PostCallRecordCmdBeginRenderPass2KHR(VkCommandBuffer commandBuffer,
1040 const VkRenderPassBeginInfo *pRenderPassBegin,
1041 const VkSubpassBeginInfo *pSubpassBeginInfo) {
1042 StateTracker::PostCallRecordCmdBeginRenderPass2KHR(commandBuffer, pRenderPassBegin, pSubpassBeginInfo);
1043 RecordCmdBeginRenderPass(commandBuffer, pRenderPassBegin, pSubpassBeginInfo);
1044}
1045
1046void SyncValidator::RecordCmdNextSubpass(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo *pSubpassBeginInfo,
1047 const VkSubpassEndInfo *pSubpassEndInfo) {
1048 auto cb_context = GetAccessContext(commandBuffer);
1049 assert(cb_context);
1050 auto cb_state = cb_context->GetCommandBufferState();
1051 if (!cb_state) return;
1052
1053 auto rp_state = cb_state->activeRenderPass;
1054 if (!rp_state) return;
1055
1056 cb_context->NextRenderPass(*rp_state);
1057}
1058
1059void SyncValidator::PostCallRecordCmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents) {
1060 StateTracker::PostCallRecordCmdNextSubpass(commandBuffer, contents);
1061 auto subpass_begin_info = lvl_init_struct<VkSubpassBeginInfo>();
1062 subpass_begin_info.contents = contents;
1063 RecordCmdNextSubpass(commandBuffer, &subpass_begin_info, nullptr);
1064}
1065
1066void SyncValidator::PostCallRecordCmdNextSubpass2(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo *pSubpassBeginInfo,
1067 const VkSubpassEndInfo *pSubpassEndInfo) {
1068 StateTracker::PostCallRecordCmdNextSubpass2(commandBuffer, pSubpassBeginInfo, pSubpassEndInfo);
1069 RecordCmdNextSubpass(commandBuffer, pSubpassBeginInfo, pSubpassEndInfo);
1070}
1071
1072void SyncValidator::PostCallRecordCmdNextSubpass2KHR(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo *pSubpassBeginInfo,
1073 const VkSubpassEndInfo *pSubpassEndInfo) {
1074 StateTracker::PostCallRecordCmdNextSubpass2KHR(commandBuffer, pSubpassBeginInfo, pSubpassEndInfo);
1075 RecordCmdNextSubpass(commandBuffer, pSubpassBeginInfo, pSubpassEndInfo);
1076}
1077
1078void SyncValidator::RecordCmdEndRenderPass(VkCommandBuffer commandBuffer, const VkSubpassEndInfo *pSubpassEndInfo) {}
1079
1080void SyncValidator::PostCallRecordCmdEndRenderPass(VkCommandBuffer commandBuffer) {
1081 StateTracker::PostCallRecordCmdEndRenderPass(commandBuffer);
1082 RecordCmdEndRenderPass(commandBuffer, nullptr);
1083}
1084
1085void SyncValidator::PostCallRecordCmdEndRenderPass2(VkCommandBuffer commandBuffer, const VkSubpassEndInfo *pSubpassEndInfo) {
1086 StateTracker::PostCallRecordCmdEndRenderPass2(commandBuffer, pSubpassEndInfo);
1087 RecordCmdEndRenderPass(commandBuffer, pSubpassEndInfo);
1088}
1089
1090void SyncValidator::PostCallRecordCmdEndRenderPass2KHR(VkCommandBuffer commandBuffer, const VkSubpassEndInfo *pSubpassEndInfo) {
1091 StateTracker::PostCallRecordCmdEndRenderPass2KHR(commandBuffer, pSubpassEndInfo);
1092 RecordCmdEndRenderPass(commandBuffer, pSubpassEndInfo);
1093}