blob: a33234d94665d4505eca11f3297dc1332fcd51ca [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 }
John Zulaufe5da6e52020-03-18 15:32:18 -0600147 if (subpass_dep.barrier_from_external) {
148 src_external_ = TrackBack(external_context, queue_flags, *subpass_dep.barrier_from_external);
149 } else {
150 src_external_ = TrackBack();
151 }
152 if (subpass_dep.barrier_to_external) {
153 dst_external_ = TrackBack(this, queue_flags, *subpass_dep.barrier_to_external);
154 } else {
155 dst_external_ = TrackBack();
John Zulauf3d84f1b2020-03-09 13:33:25 -0600156 }
John Zulauf5c5e88d2019-12-26 11:22:02 -0700157}
158
John Zulauf5f13a792020-03-10 07:31:21 -0600159template <typename Detector>
160HazardResult AccessTrackerContext::DetectPreviousHazard(const VulkanTypedHandle &handle, const Detector &detector,
161 const ResourceAccessRange &range) const {
162 ResourceAccessRangeMap descent_map;
163 ResourceAccessState default_state; // When present, PreviousAccess will "infill"
164 ResolvePreviousAccess(handle, range, &descent_map, &default_state);
165
166 HazardResult hazard;
167 for (auto prev = descent_map.begin(); prev != descent_map.end() && !hazard.hazard; ++prev) {
168 hazard = detector.Detect(prev);
169 }
170 return hazard;
171}
172
John Zulauf3d84f1b2020-03-09 13:33:25 -0600173// A recursive range walker for hazard detection, first for the current context and the (DetectHazardRecur) to walk
174// the DAG of the contexts (for example subpasses)
175template <typename Detector>
176HazardResult AccessTrackerContext::DetectHazard(const VulkanTypedHandle &handle, const Detector &detector,
John Zulauf5f13a792020-03-10 07:31:21 -0600177 const ResourceAccessRange &range) const {
John Zulauf3d84f1b2020-03-09 13:33:25 -0600178 HazardResult hazard;
John Zulauf5f13a792020-03-10 07:31:21 -0600179
180 // Async checks don't require recursive lookups, as the async lists are exhaustive for the top-level context
181 // so we'll check these first
182 for (const auto &async_context : async_) {
183 hazard = async_context->DetectAsyncHazard(handle, detector, range);
184 if (hazard.hazard) return hazard;
185 }
186
187 const auto access_tracker = GetAccessTracker(handle);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600188 if (access_tracker) {
189 const auto &accesses = access_tracker->GetCurrentAccessMap();
190 const auto from = accesses.lower_bound(range);
191 if (from != accesses.end() && from->first.intersects(range)) {
John Zulauf3d84f1b2020-03-09 13:33:25 -0600192 const auto to = accesses.upper_bound(range);
193 ResourceAccessRange gap = {range.begin, range.begin};
194 for (auto pos = from; pos != to; ++pos) {
John Zulauf5f13a792020-03-10 07:31:21 -0600195 hazard = detector.Detect(pos);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600196 if (hazard.hazard) return hazard;
197
John Zulauf5f13a792020-03-10 07:31:21 -0600198 // make sure we don't go past range
John Zulauf3d84f1b2020-03-09 13:33:25 -0600199 auto upper_bound = std::min(range.end, pos->first.end);
John Zulauf5f13a792020-03-10 07:31:21 -0600200 gap.end = upper_bound;
201
202 // TODO: After profiling we may want to change the descent logic such that we don't recur per gap...
John Zulauf3d84f1b2020-03-09 13:33:25 -0600203 if (!gap.empty()) {
204 // Must recur on all gaps
John Zulauf5f13a792020-03-10 07:31:21 -0600205 hazard = DetectPreviousHazard(handle, detector, gap);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600206 if (hazard.hazard) return hazard;
207 }
208 gap.begin = upper_bound;
209 }
John Zulauf5f13a792020-03-10 07:31:21 -0600210 gap.end = range.end;
211 if (gap.non_empty()) {
212 hazard = DetectPreviousHazard(handle, detector, gap);
213 if (hazard.hazard) return hazard;
214 }
215 } else {
216 hazard = DetectPreviousHazard(handle, detector, range);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600217 }
John Zulauf5f13a792020-03-10 07:31:21 -0600218 } else {
219 hazard = DetectPreviousHazard(handle, detector, range);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600220 }
221
222 return hazard;
223}
224
225// A non recursive range walker for the asynchronous contexts (those we have no barriers with)
226template <typename Detector>
227HazardResult AccessTrackerContext::DetectAsyncHazard(const VulkanTypedHandle &handle, const Detector &detector,
228 const ResourceAccessRange &range) const {
229 const auto access_tracker = GetAccessTracker(handle);
230 HazardResult hazard;
231 if (access_tracker) {
232 auto accesses = access_tracker->GetCurrentAccessMap();
233 const auto from = accesses.lower_bound(range);
234 const auto to = accesses.upper_bound(range);
235 for (auto pos = from; pos != to; ++pos) {
236 hazard = detector.DetectAsync(pos);
237 if (hazard.hazard) break;
238 }
239 }
240 return hazard;
241}
242
John Zulauf5f13a792020-03-10 07:31:21 -0600243void AccessTrackerContext::ResolveTrackBack(const VulkanTypedHandle &handle, const ResourceAccessRange &range,
244 const AccessTrackerContext::TrackBack &track_back, ResourceAccessRangeMap *descent_map,
John Zulaufe5da6e52020-03-18 15:32:18 -0600245 const ResourceAccessState *infill_state, bool recur_to_infill) const {
John Zulauf5f13a792020-03-10 07:31:21 -0600246 const auto *access_tracker = GetAccessTracker(handle);
247 if (access_tracker) {
248 sparse_container::parallel_iterator<ResourceAccessRangeMap, const ResourceAccessRangeMap> current(
249 *descent_map, access_tracker->GetCurrentAccessMap(), range.begin);
250 while (current->range.non_empty()) {
251 if (current->pos_B->valid) {
252 auto access_with_barrier = current->pos_B->lower_bound->second;
253 access_with_barrier.ApplyBarrier(track_back.barrier);
254 if (current->pos_A->valid) {
255 // split A to match B's range
256 const auto &dst_range = current->pos_A->lower_bound->first;
257 const auto split_range = current->range & dst_range;
258 auto dst_pos = current->pos_A->lower_bound;
John Zulauf3d84f1b2020-03-09 13:33:25 -0600259
John Zulauf5f13a792020-03-10 07:31:21 -0600260 if (split_range.begin != dst_range.begin) {
261 dst_pos = descent_map->split(dst_pos, split_range.begin, sparse_container::split_op_keep_both());
262 ++dst_pos;
263 }
264 if (split_range.end != dst_range.end) {
265 dst_pos = descent_map->split(dst_pos, split_range.end, sparse_container::split_op_keep_both());
266 }
267 if (split_range != dst_range) {
268 current.invalidate_A(); // Update the parallel iterator to point at the correct segment after split(s)
269 }
270 current->pos_A->lower_bound->second.Resolve(access_with_barrier);
271 } else {
272 descent_map->insert(current->pos_A->lower_bound, std::make_pair(current->range, access_with_barrier));
273 current.invalidate_A(); // Update the parallel iterator to point at the correct segment after split(s)
274 }
275 } else {
276 // we have to descend to fill this gap
John Zulaufe5da6e52020-03-18 15:32:18 -0600277 if (recur_to_infill) {
278 track_back.context->ResolvePreviousAccess(handle, range, descent_map, infill_state);
279 current.invalidate_A(); // Update the parallel iterator to point at the correct segment after recursion.
280 }
John Zulauf5f13a792020-03-10 07:31:21 -0600281 if (!current->pos_A->valid && infill_state) {
282 // If we didn't find anything in the previous range, we infill with default to prevent repeating
283 // a fruitless search
284 descent_map->insert(current->pos_A->lower_bound, std::make_pair(current->range, *infill_state));
285 current.invalidate_A(); // Update the parallel iterator to point at the correct segment after insert
286 }
287 }
288 ++current;
289 }
John Zulauf3d84f1b2020-03-09 13:33:25 -0600290 }
John Zulauf3d84f1b2020-03-09 13:33:25 -0600291}
292
John Zulauf5f13a792020-03-10 07:31:21 -0600293void AccessTrackerContext::ResolvePreviousAccess(const VulkanTypedHandle &handle, const ResourceAccessRange &range,
294 ResourceAccessRangeMap *descent_map,
295 const ResourceAccessState *infill_state) const {
John Zulaufe5da6e52020-03-18 15:32:18 -0600296 if ((prev_.size() == 0) && (src_external_.context == nullptr)) {
John Zulauf5f13a792020-03-10 07:31:21 -0600297 if (range.non_empty() && infill_state) {
298 descent_map->insert(std::make_pair(range, *infill_state));
299 }
300 } else {
301 // Look for something to fill the gap further along.
302 for (const auto &prev_dep : prev_) {
303 ResolveTrackBack(handle, range, prev_dep, descent_map, infill_state);
304 }
305
John Zulaufe5da6e52020-03-18 15:32:18 -0600306 if (src_external_.context) {
307 ResolveTrackBack(handle, range, src_external_, descent_map, infill_state);
John Zulauf5f13a792020-03-10 07:31:21 -0600308 }
309 }
John Zulauf3d84f1b2020-03-09 13:33:25 -0600310}
311
312class HazardDetector {
313 SyncStageAccessIndex usage_index_;
314
315 public:
John Zulauf5f13a792020-03-10 07:31:21 -0600316 HazardResult Detect(const ResourceAccessRangeMap::const_iterator &pos) const { return pos->second.DetectHazard(usage_index_); }
John Zulauf3d84f1b2020-03-09 13:33:25 -0600317 HazardResult DetectAsync(const ResourceAccessRangeMap::const_iterator &pos) const {
318 return pos->second.DetectAsyncHazard(usage_index_);
319 }
320 HazardDetector(SyncStageAccessIndex usage) : usage_index_(usage) {}
321};
322
323HazardResult AccessTrackerContext::DetectHazard(const VulkanTypedHandle &handle, SyncStageAccessIndex usage_index,
324 const ResourceAccessRange &range) const {
325 HazardDetector detector(usage_index);
326 return DetectHazard(handle, detector, range);
327}
328
329void CommandBufferAccessContext::BeginRenderPass(const RENDER_PASS_STATE &rp_state) {
330 // Create an access context for the first subpass and add it to the command buffers collection
331 render_pass_contexts_.emplace_back(queue_flags_, &rp_state.subpass_dependencies, &cb_tracker_context_);
332 current_renderpass_context_ = &render_pass_contexts_.back();
333 current_context_ = &current_renderpass_context_->CurrentContext();
John Zulaufe5da6e52020-03-18 15:32:18 -0600334
335 // TODO: Add layout load/store/transition/resolve access (here or in RenderPassContext)
John Zulauf3d84f1b2020-03-09 13:33:25 -0600336}
337
338void CommandBufferAccessContext::NextRenderPass(const RENDER_PASS_STATE &rp_state) {
339 assert(current_renderpass_context_);
340 current_renderpass_context_->NextSubpass(queue_flags_, &cb_tracker_context_);
John Zulaufe5da6e52020-03-18 15:32:18 -0600341 // TODO: Add layout load/store/transition/resolve access (here or in RenderPassContext)
John Zulauf3d84f1b2020-03-09 13:33:25 -0600342 current_context_ = &current_renderpass_context_->CurrentContext();
343}
344
John Zulaufe5da6e52020-03-18 15:32:18 -0600345void CommandBufferAccessContext::EndRenderPass(const RENDER_PASS_STATE &render_pass) {
346 std::unordered_set<VulkanTypedHandle> resolved;
347 assert(current_renderpass_context_);
348 if (!current_renderpass_context_) return;
349
350 const auto &contexts = current_renderpass_context_->subpass_contexts_;
351
352 // TODO: Add layout load/store/transition/resolve access (here or in RenderPassContext)
353
354 for (uint32_t subpass_index = 0; subpass_index < contexts.size(); subpass_index++) {
355 auto &context = contexts[subpass_index];
356 for (const auto &tracker_pair : context.GetAccessTrackerMap()) {
357 if (tracker_pair.second.GetCurrentAccessMap().size() == 0) continue;
358 auto insert_pair = resolved.insert(tracker_pair.first);
359 if (insert_pair.second) { // only create the resolve map for this handle if we haven't seen it before
360 // This is the first time we've seen this handle accessed, resolve this for all subsequent subpasses
361 ResourceAccessRangeMap resolve_map;
362 auto resolve_index = static_cast<uint32_t>(contexts.size());
363 while (resolve_index > subpass_index) {
364 resolve_index--;
365 const auto &from_context = contexts[resolve_index];
366 from_context.ResolveTrackBack(tracker_pair.first, full_range, from_context.GetDstExternalTrackBack(),
367 &resolve_map, nullptr, false);
368 }
369 // Given that all DAG paths lead back to the src_external_ (if only a default one) we can just overwrite.
370 sparse_container::splice(&cb_tracker_context_.GetAccessTracker(tracker_pair.first)->GetCurrentAccessMap(),
371 resolve_map, sparse_container::value_precedence::prefer_source);
372 // TODO: This might be a place to consolidate the map
373 }
374 }
375 }
376 current_context_ = &cb_tracker_context_;
377 current_renderpass_context_ = nullptr;
378}
379
John Zulauf3d84f1b2020-03-09 13:33:25 -0600380HazardResult AccessTrackerContext::DetectHazard(const IMAGE_STATE &image, SyncStageAccessIndex current_usage,
381 const VkImageSubresourceLayers &subresource, const VkOffset3D &offset,
382 const VkExtent3D &extent) const {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700383 // TODO: replace the encoder/generator with offset3D/extent3D aware versions
384 VkImageSubresourceRange subresource_range = {subresource.aspectMask, subresource.mipLevel, 1, subresource.baseArrayLayer,
385 subresource.layerCount};
locke-lunarg1dbbb9e2020-02-28 22:43:53 -0700386 VkExtent3D subresource_extent = GetImageSubresourceExtent(&image, &subresource);
387 subresource_adapter::OffsetRangeEncoder encoder(image.full_range, subresource_extent);
388 subresource_adapter::OffsetRangeGenerator range_gen(encoder, subresource_range, offset, extent);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600389 VulkanTypedHandle image_handle(image.image, kVulkanObjectTypeImage);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700390 for (; range_gen->non_empty(); ++range_gen) {
John Zulauf3d84f1b2020-03-09 13:33:25 -0600391 HazardResult hazard = DetectHazard(image_handle, current_usage, *range_gen);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700392 if (hazard.hazard) return hazard;
393 }
394 return HazardResult();
John Zulauf9cb530d2019-09-30 14:14:10 -0600395}
396
John Zulauf3d84f1b2020-03-09 13:33:25 -0600397class BarrierHazardDetector {
398 public:
399 BarrierHazardDetector(SyncStageAccessIndex usage_index, VkPipelineStageFlags src_exec_scope,
400 SyncStageAccessFlags src_access_scope)
401 : usage_index_(usage_index), src_exec_scope_(src_exec_scope), src_access_scope_(src_access_scope) {}
402
John Zulauf5f13a792020-03-10 07:31:21 -0600403 HazardResult Detect(const ResourceAccessRangeMap::const_iterator &pos) const {
404 return pos->second.DetectBarrierHazard(usage_index_, src_exec_scope_, src_access_scope_);
John Zulauf0cb5be22020-01-23 12:18:22 -0700405 }
John Zulauf3d84f1b2020-03-09 13:33:25 -0600406 HazardResult DetectAsync(const ResourceAccessRangeMap::const_iterator &pos) const {
407 // Async barrier hazard detection can use the same path as the usage index is not IsRead, but is IsWrite
408 return pos->second.DetectAsyncHazard(usage_index_);
409 }
410
411 private:
412 SyncStageAccessIndex usage_index_;
413 VkPipelineStageFlags src_exec_scope_;
414 SyncStageAccessFlags src_access_scope_;
415};
416
417HazardResult AccessTrackerContext::DetectBarrierHazard(const VulkanTypedHandle &handle, SyncStageAccessIndex current_usage,
418 VkPipelineStageFlags src_exec_scope, SyncStageAccessFlags src_access_scope,
419 const ResourceAccessRange &range) const {
420 BarrierHazardDetector detector(current_usage, src_exec_scope, src_access_scope);
421 return DetectHazard(handle, detector, range);
John Zulauf0cb5be22020-01-23 12:18:22 -0700422}
423
John Zulauf3d84f1b2020-03-09 13:33:25 -0600424HazardResult DetectImageBarrierHazard(const AccessTrackerContext &context, const IMAGE_STATE &image,
John Zulauf36bcf6a2020-02-03 15:12:52 -0700425 VkPipelineStageFlags src_exec_scope, SyncStageAccessFlags src_stage_accesses,
John Zulauf0cb5be22020-01-23 12:18:22 -0700426 const VkImageMemoryBarrier &barrier) {
John Zulauf0cb5be22020-01-23 12:18:22 -0700427 auto subresource_range = NormalizeSubresourceRange(image.createInfo, barrier.subresourceRange);
locke-lunarg1dbbb9e2020-02-28 22:43:53 -0700428 VkImageSubresourceLayers subresource_layers = {subresource_range.aspectMask, 0, subresource_range.baseArrayLayer,
429 subresource_range.layerCount};
John Zulauf3d84f1b2020-03-09 13:33:25 -0600430 const VulkanTypedHandle image_handle(image.image, kVulkanObjectTypeImage);
John Zulauf36bcf6a2020-02-03 15:12:52 -0700431 const auto src_access_scope = SyncStageAccess::AccessScope(src_stage_accesses, barrier.srcAccessMask);
locke-lunarg1dbbb9e2020-02-28 22:43:53 -0700432 for (uint32_t mip_index = subresource_range.baseMipLevel; mip_index < subresource_range.levelCount; mip_index++) {
433 subresource_layers.mipLevel = mip_index;
434 VkExtent3D subresource_extent = GetImageSubresourceExtent(&image, &subresource_layers);
435 subresource_adapter::OffsetRangeEncoder encoder(image.full_range, subresource_extent);
436 subresource_adapter::OffsetRangeGenerator range_gen(encoder, subresource_range, {0, 0}, subresource_extent);
437 for (; range_gen->non_empty(); ++range_gen) {
438 HazardResult hazard = context.DetectBarrierHazard(image_handle, SyncStageAccessIndex::SYNC_IMAGE_LAYOUT_TRANSITION,
439 src_exec_scope, src_access_scope, *range_gen);
440 if (hazard.hazard) return hazard;
441 }
John Zulauf0cb5be22020-01-23 12:18:22 -0700442 }
443 return HazardResult();
444}
445
John Zulauf9cb530d2019-09-30 14:14:10 -0600446template <typename Flags, typename Map>
447SyncStageAccessFlags AccessScopeImpl(Flags flag_mask, const Map &map) {
448 SyncStageAccessFlags scope = 0;
449 for (const auto &bit_scope : map) {
450 if (flag_mask < bit_scope.first) break;
451
452 if (flag_mask & bit_scope.first) {
453 scope |= bit_scope.second;
454 }
455 }
456 return scope;
457}
458
459SyncStageAccessFlags SyncStageAccess::AccessScopeByStage(VkPipelineStageFlags stages) {
460 return AccessScopeImpl(stages, syncStageAccessMaskByStageBit);
461}
462
463SyncStageAccessFlags SyncStageAccess::AccessScopeByAccess(VkAccessFlags accesses) {
464 return AccessScopeImpl(accesses, syncStageAccessMaskByAccessBit);
465}
466
467// Getting from stage mask and access mask to stage/acess masks is something we need to be good at...
468SyncStageAccessFlags SyncStageAccess::AccessScope(VkPipelineStageFlags stages, VkAccessFlags accesses) {
John Zulauf5f13a792020-03-10 07:31:21 -0600469 // The access scope is the intersection of all stage/access types possible for the enabled stages and the enables
470 // accesses (after doing a couple factoring of common terms the union of stage/access intersections is the intersections
471 // of the union of all stage/access types for all the stages and the same unions for the access mask...
John Zulauf9cb530d2019-09-30 14:14:10 -0600472 return AccessScopeByStage(stages) & AccessScopeByAccess(accesses);
473}
474
475template <typename Action>
John Zulauf5c5e88d2019-12-26 11:22:02 -0700476void UpdateMemoryAccessState(ResourceAccessRangeMap *accesses, const ResourceAccessRange &range, const Action &action) {
John Zulauf9cb530d2019-09-30 14:14:10 -0600477 // TODO -- region/mem-range accuracte update
478 auto pos = accesses->lower_bound(range);
479 if (pos == accesses->end() || !pos->first.intersects(range)) {
480 // The range is empty, fill it with a default value.
481 pos = action.Infill(accesses, pos, range);
482 } else if (range.begin < pos->first.begin) {
483 // Leading empty space, infill
John Zulauf5c5e88d2019-12-26 11:22:02 -0700484 pos = action.Infill(accesses, pos, ResourceAccessRange(range.begin, pos->first.begin));
John Zulauf9cb530d2019-09-30 14:14:10 -0600485 } else if (pos->first.begin < range.begin) {
486 // Trim the beginning if needed
487 pos = accesses->split(pos, range.begin, sparse_container::split_op_keep_both());
488 ++pos;
489 }
490
491 const auto the_end = accesses->end();
492 while ((pos != the_end) && pos->first.intersects(range)) {
493 if (pos->first.end > range.end) {
494 pos = accesses->split(pos, range.end, sparse_container::split_op_keep_both());
495 }
496
497 pos = action(accesses, pos);
498 if (pos == the_end) break;
499
500 auto next = pos;
501 ++next;
502 if ((pos->first.end < range.end) && (next != the_end) && !next->first.is_subsequent_to(pos->first)) {
503 // Need to infill if next is disjoint
504 VkDeviceSize limit = (next == the_end) ? range.end : std::min(range.end, next->first.begin);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700505 ResourceAccessRange new_range(pos->first.end, limit);
John Zulauf9cb530d2019-09-30 14:14:10 -0600506 next = action.Infill(accesses, next, new_range);
507 }
508 pos = next;
509 }
510}
511
512struct UpdateMemoryAccessStateFunctor {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700513 using Iterator = ResourceAccessRangeMap::iterator;
514 Iterator Infill(ResourceAccessRangeMap *accesses, Iterator pos, ResourceAccessRange range) const {
John Zulauf5f13a792020-03-10 07:31:21 -0600515 // this is only called on gaps, and never returns a gap.
516 ResourceAccessState default_state;
517 context.ResolvePreviousAccess(handle, range, accesses, &default_state);
518 return accesses->lower_bound(range);
John Zulauf9cb530d2019-09-30 14:14:10 -0600519 }
John Zulauf5f13a792020-03-10 07:31:21 -0600520
John Zulauf5c5e88d2019-12-26 11:22:02 -0700521 Iterator operator()(ResourceAccessRangeMap *accesses, Iterator pos) const {
John Zulauf9cb530d2019-09-30 14:14:10 -0600522 auto &access_state = pos->second;
523 access_state.Update(usage, tag);
524 return pos;
525 }
526
John Zulauf5f13a792020-03-10 07:31:21 -0600527 UpdateMemoryAccessStateFunctor(const VulkanTypedHandle &handle_, const AccessTrackerContext &context_,
528 SyncStageAccessIndex usage_, const ResourceUsageTag &tag_)
529 : handle(handle_), context(context_), usage(usage_), tag(tag_) {}
530 const VulkanTypedHandle handle;
531 const AccessTrackerContext &context;
John Zulauf9cb530d2019-09-30 14:14:10 -0600532 SyncStageAccessIndex usage;
533 const ResourceUsageTag &tag;
534};
535
536struct ApplyMemoryAccessBarrierFunctor {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700537 using Iterator = ResourceAccessRangeMap::iterator;
538 inline Iterator Infill(ResourceAccessRangeMap *accesses, Iterator pos, ResourceAccessRange range) const { return pos; }
John Zulauf9cb530d2019-09-30 14:14:10 -0600539
John Zulauf5c5e88d2019-12-26 11:22:02 -0700540 Iterator operator()(ResourceAccessRangeMap *accesses, Iterator pos) const {
John Zulauf9cb530d2019-09-30 14:14:10 -0600541 auto &access_state = pos->second;
John Zulauf36bcf6a2020-02-03 15:12:52 -0700542 access_state.ApplyMemoryAccessBarrier(src_exec_scope, src_access_scope, dst_exec_scope, dst_access_scope);
John Zulauf9cb530d2019-09-30 14:14:10 -0600543 return pos;
544 }
545
John Zulauf36bcf6a2020-02-03 15:12:52 -0700546 ApplyMemoryAccessBarrierFunctor(VkPipelineStageFlags src_exec_scope_, SyncStageAccessFlags src_access_scope_,
547 VkPipelineStageFlags dst_exec_scope_, SyncStageAccessFlags dst_access_scope_)
548 : src_exec_scope(src_exec_scope_),
549 src_access_scope(src_access_scope_),
550 dst_exec_scope(dst_exec_scope_),
551 dst_access_scope(dst_access_scope_) {}
John Zulauf9cb530d2019-09-30 14:14:10 -0600552
John Zulauf36bcf6a2020-02-03 15:12:52 -0700553 VkPipelineStageFlags src_exec_scope;
554 SyncStageAccessFlags src_access_scope;
555 VkPipelineStageFlags dst_exec_scope;
556 SyncStageAccessFlags dst_access_scope;
John Zulauf9cb530d2019-09-30 14:14:10 -0600557};
558
559struct ApplyGlobalBarrierFunctor {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700560 using Iterator = ResourceAccessRangeMap::iterator;
561 inline Iterator Infill(ResourceAccessRangeMap *accesses, Iterator pos, ResourceAccessRange range) const { return pos; }
John Zulauf9cb530d2019-09-30 14:14:10 -0600562
John Zulauf5c5e88d2019-12-26 11:22:02 -0700563 Iterator operator()(ResourceAccessRangeMap *accesses, Iterator pos) const {
John Zulauf9cb530d2019-09-30 14:14:10 -0600564 auto &access_state = pos->second;
John Zulauf36bcf6a2020-02-03 15:12:52 -0700565 access_state.ApplyExecutionBarrier(src_exec_scope, dst_exec_scope);
John Zulauf9cb530d2019-09-30 14:14:10 -0600566
567 for (const auto &functor : barrier_functor) {
568 functor(accesses, pos);
569 }
570 return pos;
571 }
572
John Zulauf36bcf6a2020-02-03 15:12:52 -0700573 ApplyGlobalBarrierFunctor(VkPipelineStageFlags src_exec_scope, VkPipelineStageFlags dst_exec_scope,
574 SyncStageAccessFlags src_stage_accesses, SyncStageAccessFlags dst_stage_accesses,
John Zulauf9cb530d2019-09-30 14:14:10 -0600575 uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers)
John Zulauf36bcf6a2020-02-03 15:12:52 -0700576 : src_exec_scope(src_exec_scope), dst_exec_scope(dst_exec_scope) {
John Zulauf9cb530d2019-09-30 14:14:10 -0600577 // Don't want to create this per tracked item, but don't want to loop through all tracked items per barrier...
578 barrier_functor.reserve(memoryBarrierCount);
579 for (uint32_t barrier_index = 0; barrier_index < memoryBarrierCount; barrier_index++) {
580 const auto &barrier = pMemoryBarriers[barrier_index];
John Zulauf36bcf6a2020-02-03 15:12:52 -0700581 barrier_functor.emplace_back(src_exec_scope, SyncStageAccess::AccessScope(src_stage_accesses, barrier.srcAccessMask),
582 dst_exec_scope, SyncStageAccess::AccessScope(dst_stage_accesses, barrier.dstAccessMask));
John Zulauf9cb530d2019-09-30 14:14:10 -0600583 }
584 }
585
John Zulauf36bcf6a2020-02-03 15:12:52 -0700586 const VkPipelineStageFlags src_exec_scope;
587 const VkPipelineStageFlags dst_exec_scope;
John Zulauf9cb530d2019-09-30 14:14:10 -0600588 std::vector<ApplyMemoryAccessBarrierFunctor> barrier_functor;
589};
590
John Zulauf3d84f1b2020-03-09 13:33:25 -0600591void AccessTrackerContext::UpdateAccessState(const VulkanTypedHandle &handle, SyncStageAccessIndex current_usage,
592 const ResourceAccessRange &range, const ResourceUsageTag &tag) {
John Zulauf5f13a792020-03-10 07:31:21 -0600593 UpdateMemoryAccessStateFunctor action(handle, *this, current_usage, tag);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600594 auto *tracker = GetAccessTracker(handle);
595 assert(tracker);
John Zulauf5f13a792020-03-10 07:31:21 -0600596 UpdateMemoryAccessState(&tracker->GetCurrentAccessMap(), range, action);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600597}
598
John Zulauf5f13a792020-03-10 07:31:21 -0600599void AccessTrackerContext::UpdateAccessState(const IMAGE_STATE &image, SyncStageAccessIndex current_usage,
600 const VkImageSubresourceLayers &subresource, const VkOffset3D &offset,
601 const VkExtent3D &extent, const ResourceUsageTag &tag) {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700602 // TODO: replace the encoder/generator with offset3D aware versions
603 VkImageSubresourceRange subresource_range = {subresource.aspectMask, subresource.mipLevel, 1, subresource.baseArrayLayer,
604 subresource.layerCount};
locke-lunarg1dbbb9e2020-02-28 22:43:53 -0700605 VkExtent3D subresource_extent = GetImageSubresourceExtent(&image, &subresource);
606 subresource_adapter::OffsetRangeEncoder encoder(image.full_range, subresource_extent);
607 subresource_adapter::OffsetRangeGenerator range_gen(encoder, subresource_range, offset, extent);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700608
John Zulauf3d84f1b2020-03-09 13:33:25 -0600609 const VulkanTypedHandle handle(image.image, kVulkanObjectTypeImage);
610 auto *tracker = GetAccessTracker(handle);
611 assert(tracker);
John Zulauf5f13a792020-03-10 07:31:21 -0600612
613 UpdateMemoryAccessStateFunctor action(handle, *this, current_usage, tag);
614 for (; range_gen->non_empty(); ++range_gen) {
615 UpdateMemoryAccessState(&tracker->GetCurrentAccessMap(), *range_gen, action);
616 }
John Zulauf3d84f1b2020-03-09 13:33:25 -0600617}
618
619SyncBarrier::SyncBarrier(VkQueueFlags queue_flags, const VkSubpassDependency2 &barrier) {
620 const auto src_stage_mask = ExpandPipelineStages(queue_flags, barrier.srcStageMask);
621 src_exec_scope = WithEarlierPipelineStages(src_stage_mask);
622 src_access_scope = SyncStageAccess::AccessScope(src_stage_mask, barrier.srcAccessMask);
623 const auto dst_stage_mask = ExpandPipelineStages(queue_flags, barrier.dstStageMask);
624 dst_exec_scope = WithLaterPipelineStages(dst_stage_mask);
625 dst_access_scope = SyncStageAccess::AccessScope(dst_stage_mask, barrier.dstAccessMask);
626}
627
628void ResourceAccessState::ApplyBarrier(const SyncBarrier &barrier) {
629 ApplyExecutionBarrier(barrier.src_exec_scope, barrier.dst_exec_scope);
630 ApplyMemoryAccessBarrier(barrier.src_exec_scope, barrier.src_access_scope, barrier.dst_exec_scope, barrier.dst_access_scope);
631}
632
633ResourceAccessState ResourceAccessState::ApplyBarrierStack(const ResourceAccessState &that, const SyncBarrierStack &barrier_stack) {
634 ResourceAccessState copy = that;
635 for (auto barrier = barrier_stack.begin(); barrier != barrier_stack.end(); ++barrier) {
636 assert(*barrier);
637 copy.ApplyBarrier(*(*barrier));
638 }
639 return copy;
640}
641
642HazardResult ResourceAccessState::DetectHazard(SyncStageAccessIndex usage_index, SyncBarrierStack *barrier_stack) const {
643 if (barrier_stack) {
644 return ApplyBarrierStack(*this, *barrier_stack).DetectHazard(usage_index);
645 }
646 return DetectHazard(usage_index);
647}
648
John Zulauf9cb530d2019-09-30 14:14:10 -0600649HazardResult ResourceAccessState::DetectHazard(SyncStageAccessIndex usage_index) const {
650 HazardResult hazard;
651 auto usage = FlagBit(usage_index);
652 if (IsRead(usage)) {
653 if (IsWriteHazard(usage)) {
654 hazard.Set(READ_AFTER_WRITE, write_tag);
655 }
656 } else {
657 // Assume write
658 // TODO determine what to do with READ-WRITE usage states if any
659 // Write-After-Write check -- if we have a previous write to test against
660 if (last_write && IsWriteHazard(usage)) {
661 hazard.Set(WRITE_AFTER_WRITE, write_tag);
662 } else {
663 // Only look for casus belli for WAR
664 const auto usage_stage = PipelineStageBit(usage_index);
665 for (uint32_t read_index = 0; read_index < last_read_count; read_index++) {
666 if (IsReadHazard(usage_stage, last_reads[read_index])) {
667 hazard.Set(WRITE_AFTER_READ, last_reads[read_index].tag);
668 break;
669 }
670 }
671 }
672 }
673 return hazard;
674}
675
John Zulauf2f952d22020-02-10 11:34:51 -0700676// Asynchronous Hazards occur between subpasses with no connection through the DAG
John Zulauf3d84f1b2020-03-09 13:33:25 -0600677HazardResult ResourceAccessState::DetectAsyncHazard(SyncStageAccessIndex usage_index) const {
John Zulauf2f952d22020-02-10 11:34:51 -0700678 HazardResult hazard;
679 auto usage = FlagBit(usage_index);
680 if (IsRead(usage)) {
681 if (last_write != 0) {
682 hazard.Set(READ_RACING_WRITE, write_tag);
683 }
684 } else {
685 if (last_write != 0) {
686 hazard.Set(WRITE_RACING_WRITE, write_tag);
687 } else if (last_read_count > 0) {
688 hazard.Set(WRITE_RACING_READ, last_reads[0].tag);
689 }
690 }
691 return hazard;
692}
693
John Zulauf36bcf6a2020-02-03 15:12:52 -0700694HazardResult ResourceAccessState::DetectBarrierHazard(SyncStageAccessIndex usage_index, VkPipelineStageFlags src_exec_scope,
John Zulauf3d84f1b2020-03-09 13:33:25 -0600695 SyncStageAccessFlags src_access_scope,
696 SyncBarrierStack *barrier_stack) const {
697 if (barrier_stack) {
698 return ApplyBarrierStack(*this, *barrier_stack).DetectBarrierHazard(usage_index, src_exec_scope, src_access_scope);
699 }
700 return DetectBarrierHazard(usage_index, src_exec_scope, src_access_scope);
701}
702
703HazardResult ResourceAccessState::DetectBarrierHazard(SyncStageAccessIndex usage_index, VkPipelineStageFlags src_exec_scope,
John Zulauf36bcf6a2020-02-03 15:12:52 -0700704 SyncStageAccessFlags src_access_scope) const {
John Zulauf0cb5be22020-01-23 12:18:22 -0700705 // Only supporting image layout transitions for now
706 assert(usage_index == SyncStageAccessIndex::SYNC_IMAGE_LAYOUT_TRANSITION);
707 HazardResult hazard;
708 if (last_write) {
709 // If the previous write is *not* in the 1st access scope
710 // *AND* the current barrier is not in the dependency chain
711 // *AND* the there is no prior memory barrier for the previous write in the dependency chain
712 // then the barrier access is unsafe (R/W after W)
John Zulauf36bcf6a2020-02-03 15:12:52 -0700713 if (((last_write & src_access_scope) == 0) && ((src_exec_scope & write_dependency_chain) == 0) && (write_barriers == 0)) {
John Zulauf0cb5be22020-01-23 12:18:22 -0700714 // TODO: Do we need a difference hazard name for this?
715 hazard.Set(WRITE_AFTER_WRITE, write_tag);
716 }
717 } else {
718 // Look at the reads
719 for (uint32_t read_index = 0; read_index < last_read_count; read_index++) {
John Zulauf36bcf6a2020-02-03 15:12:52 -0700720 const auto &read_access = last_reads[read_index];
721 // If the read stage is not in the src sync sync
722 // *AND* not execution chained with an existing sync barrier (that's the or)
723 // then the barrier access is unsafe (R/W after R)
724 if ((src_exec_scope & (read_access.stage | read_access.barriers)) == 0) {
725 hazard.Set(WRITE_AFTER_READ, read_access.tag);
John Zulauf0cb5be22020-01-23 12:18:22 -0700726 break;
727 }
728 }
729 }
730 return hazard;
731}
732
John Zulauf5f13a792020-03-10 07:31:21 -0600733// The logic behind resolves is the same as update, we assume that earlier hazards have be reported, and that no
734// tranistive hazard can exists with a hazard between the earlier operations. Yes, an early hazard can mask that another
735// exists, but if you fix *that* hazard it either fixes or unmasks the subsequent ones.
736void ResourceAccessState::Resolve(const ResourceAccessState &other) {
737 if (write_tag.IsBefore(other.write_tag)) {
738 // If this is a later write, we've reported any exsiting hazard, and we can just overwrite as the more recent operation
739 *this = other;
740 } else if (!other.write_tag.IsBefore(write_tag)) {
741 // This is the *equals* case for write operations, we merged the write barriers and the read state (but without the
742 // dependency chaining logic or any stage expansion)
743 write_barriers |= other.write_barriers;
744
745 // Merge that read states
746 for (uint32_t other_read_index = 0; other_read_index < other.last_read_count; other_read_index++) {
747 auto &other_read = other.last_reads[other_read_index];
748 if (last_read_stages & other_read.stage) {
749 // Merge in the barriers for read stages that exist in *both* this and other
750 // TODO: This is N^2 with stages... perhaps the ReadStates should be by stage index.
751 for (uint32_t my_read_index = 0; my_read_index < last_read_count; my_read_index++) {
752 auto &my_read = last_reads[my_read_index];
753 if (other_read.stage == my_read.stage) {
754 if (my_read.tag.IsBefore(other_read.tag)) {
755 my_read.tag = other_read.tag;
756 }
757 my_read.barriers |= other_read.barriers;
758 break;
759 }
760 }
761 } else {
762 // The other read stage doesn't exist in this, so add it.
763 last_reads[last_read_count] = other_read;
764 last_read_count++;
765 last_read_stages |= other_read.stage;
766 }
767 }
768 } // the else clause would be that other write is before this write... in which case we supercede the other state and ignore
769 // it.
770}
771
John Zulauf9cb530d2019-09-30 14:14:10 -0600772void ResourceAccessState::Update(SyncStageAccessIndex usage_index, const ResourceUsageTag &tag) {
773 // Move this logic in the ResourceStateTracker as methods, thereof (or we'll repeat it for every flavor of resource...
774 const auto usage_bit = FlagBit(usage_index);
775 if (IsRead(usage_index)) {
776 // Mulitple outstanding reads may be of interest and do dependency chains independently
777 // However, for purposes of barrier tracking, only one read per pipeline stage matters
778 const auto usage_stage = PipelineStageBit(usage_index);
779 if (usage_stage & last_read_stages) {
780 for (uint32_t read_index = 0; read_index < last_read_count; read_index++) {
781 ReadState &access = last_reads[read_index];
782 if (access.stage == usage_stage) {
783 access.barriers = 0;
784 access.tag = tag;
785 break;
786 }
787 }
788 } else {
789 // We don't have this stage in the list yet...
790 assert(last_read_count < last_reads.size());
791 ReadState &access = last_reads[last_read_count++];
792 access.stage = usage_stage;
793 access.barriers = 0;
794 access.tag = tag;
795 last_read_stages |= usage_stage;
796 }
797 } else {
798 // Assume write
799 // TODO determine what to do with READ-WRITE operations if any
800 // Clobber last read and both sets of barriers... because all we have is DANGER, DANGER, WILL ROBINSON!!!
801 // if the last_reads/last_write were unsafe, we've reported them,
802 // in either case the prior access is irrelevant, we can overwrite them as *this* write is now after them
803 last_read_count = 0;
804 last_read_stages = 0;
805
806 write_barriers = 0;
807 write_dependency_chain = 0;
808 write_tag = tag;
809 last_write = usage_bit;
810 }
811}
John Zulauf5f13a792020-03-10 07:31:21 -0600812
John Zulauf9cb530d2019-09-30 14:14:10 -0600813void ResourceAccessState::ApplyExecutionBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask) {
814 // Execution Barriers only protect read operations
815 for (uint32_t read_index = 0; read_index < last_read_count; read_index++) {
816 ReadState &access = last_reads[read_index];
817 // The | implements the "dependency chain" logic for this access, as the barriers field stores the second sync scope
818 if (srcStageMask & (access.stage | access.barriers)) {
819 access.barriers |= dstStageMask;
820 }
821 }
822 if (write_dependency_chain & srcStageMask) write_dependency_chain |= dstStageMask;
823}
824
John Zulauf36bcf6a2020-02-03 15:12:52 -0700825void ResourceAccessState::ApplyMemoryAccessBarrier(VkPipelineStageFlags src_exec_scope, SyncStageAccessFlags src_access_scope,
826 VkPipelineStageFlags dst_exec_scope, SyncStageAccessFlags dst_access_scope) {
John Zulauf9cb530d2019-09-30 14:14:10 -0600827 // Assuming we've applied the execution side of this barrier, we update just the write
828 // The || implements the "dependency chain" logic for this barrier
John Zulauf36bcf6a2020-02-03 15:12:52 -0700829 if ((src_access_scope & last_write) || (write_dependency_chain & src_exec_scope)) {
830 write_barriers |= dst_access_scope;
831 write_dependency_chain |= dst_exec_scope;
John Zulauf9cb530d2019-09-30 14:14:10 -0600832 }
833}
834
835void SyncValidator::ResetCommandBuffer(VkCommandBuffer command_buffer) {
John Zulauf3d84f1b2020-03-09 13:33:25 -0600836 auto *access_context = GetAccessContextNoInsert(command_buffer);
837 if (access_context) {
838 access_context->Reset();
John Zulauf9cb530d2019-09-30 14:14:10 -0600839 }
840}
841
John Zulauf3d84f1b2020-03-09 13:33:25 -0600842void SyncValidator::ApplyGlobalBarriers(AccessTrackerContext *context, VkPipelineStageFlags srcStageMask,
John Zulauf36bcf6a2020-02-03 15:12:52 -0700843 VkPipelineStageFlags dstStageMask, SyncStageAccessFlags src_access_scope,
844 SyncStageAccessFlags dst_access_scope, uint32_t memoryBarrierCount,
John Zulauf9cb530d2019-09-30 14:14:10 -0600845 const VkMemoryBarrier *pMemoryBarriers) {
846 // TODO: Implement this better (maybe some delayed/on-demand integration).
John Zulauf36bcf6a2020-02-03 15:12:52 -0700847 ApplyGlobalBarrierFunctor barriers_functor(srcStageMask, dstStageMask, src_access_scope, dst_access_scope, memoryBarrierCount,
John Zulauf9cb530d2019-09-30 14:14:10 -0600848 pMemoryBarriers);
John Zulauf5f13a792020-03-10 07:31:21 -0600849 // Note: Barriers do *not* cross context boundaries, applying to accessess within.... (at least for renderpass subpasses
John Zulauf3d84f1b2020-03-09 13:33:25 -0600850 for (auto &handle_tracker_pair : context->GetAccessTrackerMap()) {
851 UpdateMemoryAccessState(&handle_tracker_pair.second.GetCurrentAccessMap(), full_range, barriers_functor);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700852 }
John Zulauf9cb530d2019-09-30 14:14:10 -0600853}
854
John Zulauf3d84f1b2020-03-09 13:33:25 -0600855void SyncValidator::ApplyBufferBarriers(AccessTrackerContext *context, VkPipelineStageFlags src_exec_scope,
John Zulauf36bcf6a2020-02-03 15:12:52 -0700856 SyncStageAccessFlags src_stage_accesses, VkPipelineStageFlags dst_exec_scope,
857 SyncStageAccessFlags dst_stage_accesses, uint32_t barrier_count,
John Zulauf9cb530d2019-09-30 14:14:10 -0600858 const VkBufferMemoryBarrier *barriers) {
859 // TODO Implement this at subresource/memory_range accuracy
860 for (uint32_t index = 0; index < barrier_count; index++) {
861 const auto &barrier = barriers[index];
862 const auto *buffer = Get<BUFFER_STATE>(barrier.buffer);
863 if (!buffer) continue;
John Zulauf3d84f1b2020-03-09 13:33:25 -0600864 auto *tracker = context->GetAccessTracker(VulkanTypedHandle(buffer->binding.mem_state->mem, kVulkanObjectTypeDeviceMemory));
865 if (!tracker) continue;
John Zulauf5c5e88d2019-12-26 11:22:02 -0700866 ResourceAccessRange range = MakeMemoryAccessRange(*buffer, barrier.offset, barrier.size);
John Zulauf9cb530d2019-09-30 14:14:10 -0600867 UpdateMemoryAccessState(
John Zulauf3d84f1b2020-03-09 13:33:25 -0600868 &tracker->GetCurrentAccessMap(), range,
John Zulauf36bcf6a2020-02-03 15:12:52 -0700869 ApplyMemoryAccessBarrierFunctor(src_exec_scope, AccessScope(src_stage_accesses, barrier.srcAccessMask), dst_exec_scope,
870 AccessScope(dst_stage_accesses, barrier.dstAccessMask)));
John Zulauf9cb530d2019-09-30 14:14:10 -0600871 }
872}
873
John Zulauf3d84f1b2020-03-09 13:33:25 -0600874void SyncValidator::ApplyImageBarriers(AccessTrackerContext *context, VkPipelineStageFlags src_exec_scope,
John Zulauf36bcf6a2020-02-03 15:12:52 -0700875 SyncStageAccessFlags src_stage_accesses, VkPipelineStageFlags dst_exec_scope,
876 SyncStageAccessFlags dst_stage_accesses, uint32_t barrier_count,
John Zulauf5c5e88d2019-12-26 11:22:02 -0700877 const VkImageMemoryBarrier *barriers) {
878 for (uint32_t index = 0; index < barrier_count; index++) {
879 const auto &barrier = barriers[index];
880 const auto *image = Get<IMAGE_STATE>(barrier.image);
881 if (!image) continue;
John Zulauf3d84f1b2020-03-09 13:33:25 -0600882 auto tracker = context->GetAccessTrackerNoInsert(VulkanTypedHandle(barrier.image, kVulkanObjectTypeImage));
883 if (!tracker) continue;
884 auto *accesses = &tracker->GetCurrentAccessMap();
885
John Zulauf5c5e88d2019-12-26 11:22:02 -0700886 auto subresource_range = NormalizeSubresourceRange(image->createInfo, barrier.subresourceRange);
locke-lunarg1dbbb9e2020-02-28 22:43:53 -0700887 VkImageSubresourceLayers subresource_layers = {subresource_range.aspectMask, 0, subresource_range.baseArrayLayer,
888 subresource_range.layerCount};
889 for (uint32_t mip_index = subresource_range.baseMipLevel; mip_index < subresource_range.levelCount; mip_index++) {
890 subresource_layers.mipLevel = mip_index;
891 VkExtent3D subresource_extent = GetImageSubresourceExtent(image, &subresource_layers);
892 subresource_adapter::OffsetRangeEncoder encoder(image->full_range, subresource_extent);
893 subresource_adapter::OffsetRangeGenerator range_gen(encoder, subresource_range, {0, 0}, subresource_extent);
894
895 const ApplyMemoryAccessBarrierFunctor barrier_action(
896 src_exec_scope, AccessScope(src_stage_accesses, barrier.srcAccessMask), dst_exec_scope,
897 AccessScope(dst_stage_accesses, barrier.dstAccessMask));
898 for (; range_gen->non_empty(); ++range_gen) {
899 UpdateMemoryAccessState(accesses, *range_gen, barrier_action);
900 }
John Zulauf5c5e88d2019-12-26 11:22:02 -0700901 }
John Zulauf9cb530d2019-09-30 14:14:10 -0600902 }
John Zulauf9cb530d2019-09-30 14:14:10 -0600903}
904
905bool SyncValidator::PreCallValidateCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
906 uint32_t regionCount, const VkBufferCopy *pRegions) const {
907 bool skip = false;
John Zulauf3d84f1b2020-03-09 13:33:25 -0600908 const auto *cb_context = GetAccessContext(commandBuffer);
909 assert(cb_context);
910 if (!cb_context) return skip;
911 const auto *context = cb_context->GetCurrentAccessContext();
John Zulauf9cb530d2019-09-30 14:14:10 -0600912
John Zulauf3d84f1b2020-03-09 13:33:25 -0600913 // If we have no previous accesses, we have no hazards
914 // TODO: make this sub-resource capable
915 // TODO: make this general, and stuff it into templates/utility functions
916 const auto *src_buffer = Get<BUFFER_STATE>(srcBuffer);
917 const auto src_mem = (src_buffer && !src_buffer->sparse) ? src_buffer->binding.mem_state->mem : VK_NULL_HANDLE;
918 const auto *dst_buffer = Get<BUFFER_STATE>(dstBuffer);
919 const auto dst_mem = (dst_buffer && !dst_buffer->sparse) ? dst_buffer->binding.mem_state->mem : VK_NULL_HANDLE;
920
921 for (uint32_t region = 0; region < regionCount; region++) {
922 const auto &copy_region = pRegions[region];
923 if (src_mem != VK_NULL_HANDLE) {
924 ResourceAccessRange src_range = MakeMemoryAccessRange(*src_buffer, copy_region.srcOffset, copy_region.size);
925 auto hazard = context->DetectHazard(VulkanTypedHandle(src_mem, kVulkanObjectTypeDeviceMemory),
926 SYNC_TRANSFER_TRANSFER_READ, src_range);
927 if (hazard.hazard) {
928 // TODO -- add tag information to log msg when useful.
locke-lunarga0003652020-03-10 11:38:51 -0600929 skip |= LogError(srcBuffer, string_SyncHazardVUID(hazard.hazard),
930 "vkCmdCopyBuffer: Hazard %s for srcBuffer %s, region %" PRIu32, string_SyncHazard(hazard.hazard),
931 report_data->FormatHandle(srcBuffer).c_str(), region);
John Zulauf9cb530d2019-09-30 14:14:10 -0600932 }
John Zulauf9cb530d2019-09-30 14:14:10 -0600933 }
John Zulauf3d84f1b2020-03-09 13:33:25 -0600934 if ((dst_mem != VK_NULL_HANDLE) && !skip) {
935 ResourceAccessRange dst_range = MakeMemoryAccessRange(*dst_buffer, copy_region.dstOffset, copy_region.size);
936 auto hazard = context->DetectHazard(VulkanTypedHandle(dst_mem, kVulkanObjectTypeDeviceMemory),
937 SYNC_TRANSFER_TRANSFER_WRITE, dst_range);
938 if (hazard.hazard) {
locke-lunarga0003652020-03-10 11:38:51 -0600939 skip |= LogError(dstBuffer, string_SyncHazardVUID(hazard.hazard),
940 "vkCmdCopyBuffer: Hazard %s for dstBuffer %s, region %" PRIu32, string_SyncHazard(hazard.hazard),
941 report_data->FormatHandle(dstBuffer).c_str(), region);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600942 }
943 }
944 if (skip) break;
John Zulauf9cb530d2019-09-30 14:14:10 -0600945 }
946 return skip;
947}
948
949void SyncValidator::PreCallRecordCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
950 uint32_t regionCount, const VkBufferCopy *pRegions) {
John Zulauf3d84f1b2020-03-09 13:33:25 -0600951 auto *cb_context = GetAccessContext(commandBuffer);
952 assert(cb_context);
953 auto *context = cb_context->GetCurrentAccessContext();
954
John Zulauf9cb530d2019-09-30 14:14:10 -0600955 const auto *src_buffer = Get<BUFFER_STATE>(srcBuffer);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600956 const auto src_mem = (src_buffer && !src_buffer->sparse) ? src_buffer->binding.mem_state->mem : VK_NULL_HANDLE;
957 const VulkanTypedHandle src_handle(src_mem, kVulkanObjectTypeDeviceMemory);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600958
John Zulauf9cb530d2019-09-30 14:14:10 -0600959 const auto *dst_buffer = Get<BUFFER_STATE>(dstBuffer);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600960 const auto dst_mem = (dst_buffer && !dst_buffer->sparse) ? dst_buffer->binding.mem_state->mem : VK_NULL_HANDLE;
961 const VulkanTypedHandle dst_handle(dst_mem, kVulkanObjectTypeDeviceMemory);
John Zulauf9cb530d2019-09-30 14:14:10 -0600962
963 for (uint32_t region = 0; region < regionCount; region++) {
964 const auto &copy_region = pRegions[region];
John Zulauf3d84f1b2020-03-09 13:33:25 -0600965 if (src_mem) {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700966 ResourceAccessRange src_range = MakeMemoryAccessRange(*src_buffer, copy_region.srcOffset, copy_region.size);
John Zulauf5f13a792020-03-10 07:31:21 -0600967 context->UpdateAccessState(src_handle, SYNC_TRANSFER_TRANSFER_READ, src_range, tag);
John Zulauf9cb530d2019-09-30 14:14:10 -0600968 }
John Zulauf3d84f1b2020-03-09 13:33:25 -0600969 if (dst_mem) {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700970 ResourceAccessRange dst_range = MakeMemoryAccessRange(*dst_buffer, copy_region.dstOffset, copy_region.size);
John Zulauf5f13a792020-03-10 07:31:21 -0600971 context->UpdateAccessState(dst_handle, SYNC_TRANSFER_TRANSFER_WRITE, dst_range, tag);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700972 }
973 }
974}
975
976bool SyncValidator::PreCallValidateCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
977 VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
978 const VkImageCopy *pRegions) const {
979 bool skip = false;
John Zulauf3d84f1b2020-03-09 13:33:25 -0600980 const auto *cb_access_context = GetAccessContext(commandBuffer);
981 assert(cb_access_context);
982 if (!cb_access_context) return skip;
John Zulauf5c5e88d2019-12-26 11:22:02 -0700983
John Zulauf3d84f1b2020-03-09 13:33:25 -0600984 const auto *context = cb_access_context->GetCurrentAccessContext();
985 assert(context);
986 if (!context) return skip;
987
988 const auto *src_image = Get<IMAGE_STATE>(srcImage);
989 const auto *dst_image = Get<IMAGE_STATE>(dstImage);
990
991 for (uint32_t region = 0; region < regionCount; region++) {
992 const auto &copy_region = pRegions[region];
993 if (src_image) {
994 auto hazard = context->DetectHazard(*src_image, SYNC_TRANSFER_TRANSFER_READ, copy_region.srcSubresource,
995 copy_region.srcOffset, copy_region.extent);
996 if (hazard.hazard) {
locke-lunarga0003652020-03-10 11:38:51 -0600997 skip |= LogError(srcImage, string_SyncHazardVUID(hazard.hazard),
998 "vkCmdCopyImage: Hazard %s for srcImage %s, region %" PRIu32, string_SyncHazard(hazard.hazard),
999 report_data->FormatHandle(srcImage).c_str(), region);
John Zulauf5c5e88d2019-12-26 11:22:02 -07001000 }
John Zulauf3d84f1b2020-03-09 13:33:25 -06001001 }
1002
1003 if (dst_image) {
locke-lunarg1df1f882020-03-02 16:42:08 -07001004 VkExtent3D dst_copy_extent =
1005 GetAdjustedDestImageExtent(src_image->createInfo.format, dst_image->createInfo.format, copy_region.extent);
John Zulauf3d84f1b2020-03-09 13:33:25 -06001006 auto hazard = context->DetectHazard(*dst_image, SYNC_TRANSFER_TRANSFER_WRITE, copy_region.dstSubresource,
locke-lunarg1df1f882020-03-02 16:42:08 -07001007 copy_region.dstOffset, dst_copy_extent);
John Zulauf3d84f1b2020-03-09 13:33:25 -06001008 if (hazard.hazard) {
locke-lunarga0003652020-03-10 11:38:51 -06001009 skip |= LogError(dstImage, string_SyncHazardVUID(hazard.hazard),
1010 "vkCmdCopyImage: Hazard %s for dstImage %s, region %" PRIu32, string_SyncHazard(hazard.hazard),
1011 report_data->FormatHandle(dstImage).c_str(), region);
John Zulauf5c5e88d2019-12-26 11:22:02 -07001012 }
locke-lunarg1dbbb9e2020-02-28 22:43:53 -07001013 if (skip) break;
John Zulauf5c5e88d2019-12-26 11:22:02 -07001014 }
1015 }
John Zulauf3d84f1b2020-03-09 13:33:25 -06001016
John Zulauf5c5e88d2019-12-26 11:22:02 -07001017 return skip;
1018}
1019
1020void SyncValidator::PreCallRecordCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
1021 VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
1022 const VkImageCopy *pRegions) {
John Zulauf3d84f1b2020-03-09 13:33:25 -06001023 auto *cb_access_context = GetAccessContext(commandBuffer);
1024 assert(cb_access_context);
1025 auto *context = cb_access_context->GetCurrentAccessContext();
1026 assert(context);
1027
John Zulauf5c5e88d2019-12-26 11:22:02 -07001028 auto *src_image = Get<IMAGE_STATE>(srcImage);
John Zulauf5c5e88d2019-12-26 11:22:02 -07001029 auto *dst_image = Get<IMAGE_STATE>(dstImage);
John Zulauf5c5e88d2019-12-26 11:22:02 -07001030
1031 for (uint32_t region = 0; region < regionCount; region++) {
1032 const auto &copy_region = pRegions[region];
John Zulauf3d84f1b2020-03-09 13:33:25 -06001033 if (src_image) {
John Zulauf5f13a792020-03-10 07:31:21 -06001034 context->UpdateAccessState(*src_image, SYNC_TRANSFER_TRANSFER_READ, copy_region.srcSubresource, copy_region.srcOffset,
1035 copy_region.extent, tag);
John Zulauf5c5e88d2019-12-26 11:22:02 -07001036 }
John Zulauf3d84f1b2020-03-09 13:33:25 -06001037 if (dst_image) {
locke-lunarg1df1f882020-03-02 16:42:08 -07001038 VkExtent3D dst_copy_extent =
1039 GetAdjustedDestImageExtent(src_image->createInfo.format, dst_image->createInfo.format, copy_region.extent);
John Zulauf5f13a792020-03-10 07:31:21 -06001040 context->UpdateAccessState(*dst_image, SYNC_TRANSFER_TRANSFER_WRITE, copy_region.dstSubresource, copy_region.dstOffset,
1041 dst_copy_extent, tag);
John Zulauf9cb530d2019-09-30 14:14:10 -06001042 }
1043 }
1044}
1045
1046bool SyncValidator::PreCallValidateCmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask,
1047 VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags,
1048 uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
1049 uint32_t bufferMemoryBarrierCount,
1050 const VkBufferMemoryBarrier *pBufferMemoryBarriers,
1051 uint32_t imageMemoryBarrierCount,
1052 const VkImageMemoryBarrier *pImageMemoryBarriers) const {
1053 bool skip = false;
John Zulauf3d84f1b2020-03-09 13:33:25 -06001054 const auto *cb_access_context = GetAccessContext(commandBuffer);
1055 assert(cb_access_context);
1056 if (!cb_access_context) return skip;
John Zulauf0cb5be22020-01-23 12:18:22 -07001057
John Zulauf3d84f1b2020-03-09 13:33:25 -06001058 const auto *context = cb_access_context->GetCurrentAccessContext();
1059 assert(context);
1060 if (!context) return skip;
John Zulauf0cb5be22020-01-23 12:18:22 -07001061
John Zulauf3d84f1b2020-03-09 13:33:25 -06001062 const auto src_stage_mask = ExpandPipelineStages(cb_access_context->GetQueueFlags(), srcStageMask);
John Zulauf36bcf6a2020-02-03 15:12:52 -07001063 const auto src_exec_scope = WithEarlierPipelineStages(src_stage_mask);
1064 auto src_stage_accesses = AccessScopeByStage(src_stage_mask);
John Zulauf0cb5be22020-01-23 12:18:22 -07001065 // Validate Image Layout transitions
1066 for (uint32_t index = 0; index < imageMemoryBarrierCount; index++) {
1067 const auto &barrier = pImageMemoryBarriers[index];
1068 if (barrier.newLayout == barrier.oldLayout) continue; // Only interested in layout transitions at this point.
1069 const auto *image_state = Get<IMAGE_STATE>(barrier.image);
1070 if (!image_state) continue;
John Zulauf3d84f1b2020-03-09 13:33:25 -06001071 const auto hazard = DetectImageBarrierHazard(*context, *image_state, src_exec_scope, src_stage_accesses, barrier);
John Zulauf0cb5be22020-01-23 12:18:22 -07001072 if (hazard.hazard) {
1073 // TODO -- add tag information to log msg when useful.
locke-lunarga0003652020-03-10 11:38:51 -06001074 skip |= LogError(barrier.image, string_SyncHazardVUID(hazard.hazard),
1075 "vkCmdPipelineBarrier: Hazard %s for image barrier %" PRIu32 " %s", string_SyncHazard(hazard.hazard),
1076 index, report_data->FormatHandle(barrier.image).c_str());
John Zulauf0cb5be22020-01-23 12:18:22 -07001077 }
1078 }
John Zulauf9cb530d2019-09-30 14:14:10 -06001079
1080 return skip;
1081}
1082
1083void SyncValidator::PreCallRecordCmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask,
1084 VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags,
1085 uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
1086 uint32_t bufferMemoryBarrierCount,
1087 const VkBufferMemoryBarrier *pBufferMemoryBarriers,
1088 uint32_t imageMemoryBarrierCount,
1089 const VkImageMemoryBarrier *pImageMemoryBarriers) {
John Zulauf3d84f1b2020-03-09 13:33:25 -06001090 auto *cb_access_context = GetAccessContext(commandBuffer);
1091 assert(cb_access_context);
1092 if (!cb_access_context) return;
1093 auto access_context = cb_access_context->GetCurrentAccessContext();
1094 assert(access_context);
1095 if (!access_context) return;
John Zulauf9cb530d2019-09-30 14:14:10 -06001096
John Zulauf3d84f1b2020-03-09 13:33:25 -06001097 const auto src_stage_mask = ExpandPipelineStages(cb_access_context->GetQueueFlags(), srcStageMask);
John Zulauf36bcf6a2020-02-03 15:12:52 -07001098 auto src_stage_accesses = AccessScopeByStage(src_stage_mask);
John Zulauf3d84f1b2020-03-09 13:33:25 -06001099 const auto dst_stage_mask = ExpandPipelineStages(cb_access_context->GetQueueFlags(), dstStageMask);
John Zulauf36bcf6a2020-02-03 15:12:52 -07001100 auto dst_stage_accesses = AccessScopeByStage(dst_stage_mask);
1101 const auto src_exec_scope = WithEarlierPipelineStages(src_stage_mask);
1102 const auto dst_exec_scope = WithLaterPipelineStages(dst_stage_mask);
John Zulauf3d84f1b2020-03-09 13:33:25 -06001103 ApplyBufferBarriers(access_context, src_exec_scope, src_stage_accesses, dst_exec_scope, dst_stage_accesses,
1104 bufferMemoryBarrierCount, pBufferMemoryBarriers);
1105 ApplyImageBarriers(access_context, src_exec_scope, src_stage_accesses, dst_exec_scope, dst_stage_accesses,
1106 imageMemoryBarrierCount, pImageMemoryBarriers);
John Zulauf9cb530d2019-09-30 14:14:10 -06001107
1108 // 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 -06001109 ApplyGlobalBarriers(access_context, src_exec_scope, dst_exec_scope, src_stage_accesses, dst_stage_accesses, memoryBarrierCount,
John Zulauf0cb5be22020-01-23 12:18:22 -07001110 pMemoryBarriers);
John Zulauf9cb530d2019-09-30 14:14:10 -06001111}
1112
1113void SyncValidator::PostCallRecordCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo,
1114 const VkAllocationCallbacks *pAllocator, VkDevice *pDevice, VkResult result) {
1115 // The state tracker sets up the device state
1116 StateTracker::PostCallRecordCreateDevice(gpu, pCreateInfo, pAllocator, pDevice, result);
1117
John Zulauf5f13a792020-03-10 07:31:21 -06001118 // Add the callback hooks for the functions that are either broadly or deeply used and that the ValidationStateTracker
1119 // refactor would be messier without.
John Zulauf9cb530d2019-09-30 14:14:10 -06001120 // TODO: Find a good way to do this hooklessly.
1121 ValidationObject *device_object = GetLayerDataPtr(get_dispatch_key(*pDevice), layer_data_map);
1122 ValidationObject *validation_data = GetValidationObject(device_object->object_dispatch, LayerObjectTypeSyncValidation);
1123 SyncValidator *sync_device_state = static_cast<SyncValidator *>(validation_data);
1124
1125 sync_device_state->SetCommandBufferResetCallback(
1126 [sync_device_state](VkCommandBuffer command_buffer) -> void { sync_device_state->ResetCommandBuffer(command_buffer); });
1127}
John Zulauf3d84f1b2020-03-09 13:33:25 -06001128
1129void SyncValidator::PostCallRecordBeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo,
1130 VkResult result) {
1131 // The state tracker sets up the command buffer state
1132 StateTracker::PostCallRecordBeginCommandBuffer(commandBuffer, pBeginInfo, result);
1133
1134 // Create/initialize the structure that trackers accesses at the command buffer scope.
1135 auto cb_access_context = GetAccessContext(commandBuffer);
1136 assert(cb_access_context);
1137 cb_access_context->Reset();
1138}
1139
1140void SyncValidator::RecordCmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
1141 const VkSubpassBeginInfo *pSubpassBeginInfo) {
1142 const auto rp_state = Get<RENDER_PASS_STATE>(pRenderPassBegin->renderPass);
1143 auto cb_context = GetAccessContext(commandBuffer);
1144 if (rp_state && cb_context) {
1145 cb_context->BeginRenderPass(*rp_state);
1146 }
1147}
1148
1149void SyncValidator::PostCallRecordCmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
1150 VkSubpassContents contents) {
1151 StateTracker::PostCallRecordCmdBeginRenderPass(commandBuffer, pRenderPassBegin, contents);
1152 auto subpass_begin_info = lvl_init_struct<VkSubpassBeginInfo>();
1153 subpass_begin_info.contents = contents;
1154 RecordCmdBeginRenderPass(commandBuffer, pRenderPassBegin, &subpass_begin_info);
1155}
1156
1157void SyncValidator::PostCallRecordCmdBeginRenderPass2(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
1158 const VkSubpassBeginInfo *pSubpassBeginInfo) {
1159 StateTracker::PostCallRecordCmdBeginRenderPass2(commandBuffer, pRenderPassBegin, pSubpassBeginInfo);
1160 RecordCmdBeginRenderPass(commandBuffer, pRenderPassBegin, pSubpassBeginInfo);
1161}
1162
1163void SyncValidator::PostCallRecordCmdBeginRenderPass2KHR(VkCommandBuffer commandBuffer,
1164 const VkRenderPassBeginInfo *pRenderPassBegin,
1165 const VkSubpassBeginInfo *pSubpassBeginInfo) {
1166 StateTracker::PostCallRecordCmdBeginRenderPass2KHR(commandBuffer, pRenderPassBegin, pSubpassBeginInfo);
1167 RecordCmdBeginRenderPass(commandBuffer, pRenderPassBegin, pSubpassBeginInfo);
1168}
1169
1170void SyncValidator::RecordCmdNextSubpass(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo *pSubpassBeginInfo,
1171 const VkSubpassEndInfo *pSubpassEndInfo) {
1172 auto cb_context = GetAccessContext(commandBuffer);
1173 assert(cb_context);
1174 auto cb_state = cb_context->GetCommandBufferState();
1175 if (!cb_state) return;
1176
1177 auto rp_state = cb_state->activeRenderPass;
1178 if (!rp_state) return;
1179
1180 cb_context->NextRenderPass(*rp_state);
1181}
1182
1183void SyncValidator::PostCallRecordCmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents) {
1184 StateTracker::PostCallRecordCmdNextSubpass(commandBuffer, contents);
1185 auto subpass_begin_info = lvl_init_struct<VkSubpassBeginInfo>();
1186 subpass_begin_info.contents = contents;
1187 RecordCmdNextSubpass(commandBuffer, &subpass_begin_info, nullptr);
1188}
1189
1190void SyncValidator::PostCallRecordCmdNextSubpass2(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo *pSubpassBeginInfo,
1191 const VkSubpassEndInfo *pSubpassEndInfo) {
1192 StateTracker::PostCallRecordCmdNextSubpass2(commandBuffer, pSubpassBeginInfo, pSubpassEndInfo);
1193 RecordCmdNextSubpass(commandBuffer, pSubpassBeginInfo, pSubpassEndInfo);
1194}
1195
1196void SyncValidator::PostCallRecordCmdNextSubpass2KHR(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo *pSubpassBeginInfo,
1197 const VkSubpassEndInfo *pSubpassEndInfo) {
1198 StateTracker::PostCallRecordCmdNextSubpass2KHR(commandBuffer, pSubpassBeginInfo, pSubpassEndInfo);
1199 RecordCmdNextSubpass(commandBuffer, pSubpassBeginInfo, pSubpassEndInfo);
1200}
1201
John Zulaufe5da6e52020-03-18 15:32:18 -06001202void SyncValidator::RecordCmdEndRenderPass(VkCommandBuffer commandBuffer, const VkSubpassEndInfo *pSubpassEndInfo) {
1203 // Resolve the all subpass contexts to the command buffer contexts
1204 auto cb_context = GetAccessContext(commandBuffer);
1205 assert(cb_context);
1206 auto cb_state = cb_context->GetCommandBufferState();
1207 if (!cb_state) return;
1208
1209 const auto *rp_state = cb_state->activeRenderPass;
1210 if (!rp_state) return;
1211
1212 cb_context->EndRenderPass(*rp_state);
1213}
John Zulauf3d84f1b2020-03-09 13:33:25 -06001214
1215void SyncValidator::PostCallRecordCmdEndRenderPass(VkCommandBuffer commandBuffer) {
1216 StateTracker::PostCallRecordCmdEndRenderPass(commandBuffer);
1217 RecordCmdEndRenderPass(commandBuffer, nullptr);
1218}
1219
1220void SyncValidator::PostCallRecordCmdEndRenderPass2(VkCommandBuffer commandBuffer, const VkSubpassEndInfo *pSubpassEndInfo) {
1221 StateTracker::PostCallRecordCmdEndRenderPass2(commandBuffer, pSubpassEndInfo);
1222 RecordCmdEndRenderPass(commandBuffer, pSubpassEndInfo);
1223}
1224
1225void SyncValidator::PostCallRecordCmdEndRenderPass2KHR(VkCommandBuffer commandBuffer, const VkSubpassEndInfo *pSubpassEndInfo) {
1226 StateTracker::PostCallRecordCmdEndRenderPass2KHR(commandBuffer, pSubpassEndInfo);
1227 RecordCmdEndRenderPass(commandBuffer, pSubpassEndInfo);
1228}
locke-lunarga19c71d2020-03-02 18:17:04 -07001229
1230bool SyncValidator::PreCallValidateCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage,
1231 VkImageLayout dstImageLayout, uint32_t regionCount,
1232 const VkBufferImageCopy *pRegions) const {
1233 bool skip = false;
1234 const auto *cb_access_context = GetAccessContext(commandBuffer);
1235 assert(cb_access_context);
1236 if (!cb_access_context) return skip;
1237
1238 const auto *context = cb_access_context->GetCurrentAccessContext();
1239 assert(context);
1240 if (!context) return skip;
1241
1242 const auto *src_buffer = Get<BUFFER_STATE>(srcBuffer);
1243 const auto src_mem = (src_buffer && !src_buffer->sparse) ? src_buffer->binding.mem_state->mem : VK_NULL_HANDLE;
1244 const auto *dst_image = Get<IMAGE_STATE>(dstImage);
1245
1246 for (uint32_t region = 0; region < regionCount; region++) {
1247 const auto &copy_region = pRegions[region];
1248 if (src_mem) {
1249 ResourceAccessRange src_range = MakeMemoryAccessRange(
1250 *src_buffer, copy_region.bufferOffset, GetBufferSizeFromCopyImage(copy_region, dst_image->createInfo.format));
1251 auto hazard = context->DetectHazard(VulkanTypedHandle(src_mem, kVulkanObjectTypeDeviceMemory),
1252 SYNC_TRANSFER_TRANSFER_READ, src_range);
1253 if (hazard.hazard) {
1254 // TODO -- add tag information to log msg when useful.
locke-lunarga0003652020-03-10 11:38:51 -06001255 skip |= LogError(srcBuffer, string_SyncHazardVUID(hazard.hazard),
1256 "vkCmdCopyBufferToImage: Hazard %s for srcBuffer %s, region %" PRIu32,
locke-lunarga19c71d2020-03-02 18:17:04 -07001257 string_SyncHazard(hazard.hazard), report_data->FormatHandle(srcBuffer).c_str(), region);
1258 }
1259 }
1260 if (dst_image) {
1261 auto hazard = context->DetectHazard(*dst_image, SYNC_TRANSFER_TRANSFER_WRITE, copy_region.imageSubresource,
1262 copy_region.imageOffset, copy_region.imageExtent);
1263 if (hazard.hazard) {
locke-lunarga0003652020-03-10 11:38:51 -06001264 skip |= LogError(dstImage, string_SyncHazardVUID(hazard.hazard),
1265 "vkCmdCopyBufferToImage: Hazard %s for dstImage %s, region %" PRIu32,
locke-lunarga19c71d2020-03-02 18:17:04 -07001266 string_SyncHazard(hazard.hazard), report_data->FormatHandle(dstImage).c_str(), region);
1267 }
1268 if (skip) break;
1269 }
1270 if (skip) break;
1271 }
1272 return skip;
1273}
1274
1275void SyncValidator::PreCallRecordCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage,
1276 VkImageLayout dstImageLayout, uint32_t regionCount,
1277 const VkBufferImageCopy *pRegions) {
1278 auto *cb_access_context = GetAccessContext(commandBuffer);
1279 assert(cb_access_context);
1280 auto *context = cb_access_context->GetCurrentAccessContext();
1281 assert(context);
1282
1283 const auto *src_buffer = Get<BUFFER_STATE>(srcBuffer);
1284 const auto src_mem = (src_buffer && !src_buffer->sparse) ? src_buffer->binding.mem_state->mem : VK_NULL_HANDLE;
1285 const VulkanTypedHandle src_handle(src_mem, kVulkanObjectTypeDeviceMemory);
John Zulauf5f13a792020-03-10 07:31:21 -06001286
locke-lunarga19c71d2020-03-02 18:17:04 -07001287 auto *dst_image = Get<IMAGE_STATE>(dstImage);
locke-lunarga19c71d2020-03-02 18:17:04 -07001288
1289 for (uint32_t region = 0; region < regionCount; region++) {
1290 const auto &copy_region = pRegions[region];
1291 if (src_buffer) {
1292 ResourceAccessRange src_range = MakeMemoryAccessRange(
1293 *src_buffer, copy_region.bufferOffset, GetBufferSizeFromCopyImage(copy_region, dst_image->createInfo.format));
John Zulauf5f13a792020-03-10 07:31:21 -06001294 context->UpdateAccessState(src_handle, SYNC_TRANSFER_TRANSFER_READ, src_range, tag);
locke-lunarga19c71d2020-03-02 18:17:04 -07001295 }
1296 if (dst_image) {
John Zulauf5f13a792020-03-10 07:31:21 -06001297 context->UpdateAccessState(*dst_image, SYNC_TRANSFER_TRANSFER_WRITE, copy_region.imageSubresource,
1298 copy_region.imageOffset, copy_region.imageExtent, tag);
locke-lunarga19c71d2020-03-02 18:17:04 -07001299 }
1300 }
1301}
1302
1303bool SyncValidator::PreCallValidateCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage,
1304 VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount,
1305 const VkBufferImageCopy *pRegions) const {
1306 bool skip = false;
1307 const auto *cb_access_context = GetAccessContext(commandBuffer);
1308 assert(cb_access_context);
1309 if (!cb_access_context) return skip;
1310
1311 const auto *context = cb_access_context->GetCurrentAccessContext();
1312 assert(context);
1313 if (!context) return skip;
1314
1315 const auto *src_image = Get<IMAGE_STATE>(srcImage);
1316 const auto *dst_buffer = Get<BUFFER_STATE>(dstBuffer);
1317 const auto dst_mem = (dst_buffer && !dst_buffer->sparse) ? dst_buffer->binding.mem_state->mem : VK_NULL_HANDLE;
1318 for (uint32_t region = 0; region < regionCount; region++) {
1319 const auto &copy_region = pRegions[region];
1320 if (src_image) {
1321 auto hazard = context->DetectHazard(*src_image, SYNC_TRANSFER_TRANSFER_READ, copy_region.imageSubresource,
1322 copy_region.imageOffset, copy_region.imageExtent);
1323 if (hazard.hazard) {
locke-lunarga0003652020-03-10 11:38:51 -06001324 skip |= LogError(srcImage, string_SyncHazardVUID(hazard.hazard),
1325 "vkCmdCopyImageToBuffer: Hazard %s for srcImage %s, region %" PRIu32,
locke-lunarga19c71d2020-03-02 18:17:04 -07001326 string_SyncHazard(hazard.hazard), report_data->FormatHandle(srcImage).c_str(), region);
1327 }
1328 }
1329 if (dst_mem) {
1330 ResourceAccessRange dst_range = MakeMemoryAccessRange(
1331 *dst_buffer, copy_region.bufferOffset, GetBufferSizeFromCopyImage(copy_region, src_image->createInfo.format));
1332 auto hazard = context->DetectHazard(VulkanTypedHandle(dst_mem, kVulkanObjectTypeDeviceMemory),
1333 SYNC_TRANSFER_TRANSFER_WRITE, dst_range);
1334 if (hazard.hazard) {
locke-lunarga0003652020-03-10 11:38:51 -06001335 skip |= LogError(dstBuffer, string_SyncHazardVUID(hazard.hazard),
1336 "vkCmdCopyImageToBuffer: Hazard %s for dstBuffer %s, region %" PRIu32,
locke-lunarga19c71d2020-03-02 18:17:04 -07001337 string_SyncHazard(hazard.hazard), report_data->FormatHandle(dstBuffer).c_str(), region);
1338 }
1339 }
1340 if (skip) break;
1341 }
1342 return skip;
1343}
1344
1345void SyncValidator::PreCallRecordCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
1346 VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy *pRegions) {
1347 auto *cb_access_context = GetAccessContext(commandBuffer);
1348 assert(cb_access_context);
1349 auto *context = cb_access_context->GetCurrentAccessContext();
1350 assert(context);
1351
1352 const auto *src_image = Get<IMAGE_STATE>(srcImage);
locke-lunarga19c71d2020-03-02 18:17:04 -07001353 auto *dst_buffer = Get<BUFFER_STATE>(dstBuffer);
1354 const auto dst_mem = (dst_buffer && !dst_buffer->sparse) ? dst_buffer->binding.mem_state->mem : VK_NULL_HANDLE;
John Zulauf5f13a792020-03-10 07:31:21 -06001355 const VulkanTypedHandle dst_handle(dst_mem, kVulkanObjectTypeDeviceMemory);
locke-lunarga19c71d2020-03-02 18:17:04 -07001356
1357 for (uint32_t region = 0; region < regionCount; region++) {
1358 const auto &copy_region = pRegions[region];
1359 if (src_image) {
John Zulauf5f13a792020-03-10 07:31:21 -06001360 context->UpdateAccessState(*src_image, SYNC_TRANSFER_TRANSFER_READ, copy_region.imageSubresource,
1361 copy_region.imageOffset, copy_region.imageExtent, tag);
locke-lunarga19c71d2020-03-02 18:17:04 -07001362 }
1363 if (dst_buffer) {
1364 ResourceAccessRange dst_range = MakeMemoryAccessRange(
1365 *dst_buffer, copy_region.bufferOffset, GetBufferSizeFromCopyImage(copy_region, src_image->createInfo.format));
John Zulauf5f13a792020-03-10 07:31:21 -06001366 context->UpdateAccessState(dst_handle, SYNC_TRANSFER_TRANSFER_WRITE, dst_range, tag);
locke-lunarga19c71d2020-03-02 18:17:04 -07001367 }
1368 }
1369}
1370
1371bool SyncValidator::PreCallValidateCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
1372 VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
1373 const VkImageBlit *pRegions, VkFilter filter) const {
1374 bool skip = false;
1375 const auto *cb_access_context = GetAccessContext(commandBuffer);
1376 assert(cb_access_context);
1377 if (!cb_access_context) return skip;
1378
1379 const auto *context = cb_access_context->GetCurrentAccessContext();
1380 assert(context);
1381 if (!context) return skip;
1382
1383 const auto *src_image = Get<IMAGE_STATE>(srcImage);
1384 const auto *dst_image = Get<IMAGE_STATE>(dstImage);
1385
1386 for (uint32_t region = 0; region < regionCount; region++) {
1387 const auto &blit_region = pRegions[region];
1388 if (src_image) {
1389 VkExtent3D extent = {static_cast<uint32_t>(blit_region.srcOffsets[1].x - blit_region.srcOffsets[0].x),
1390 static_cast<uint32_t>(blit_region.srcOffsets[1].y - blit_region.srcOffsets[0].y),
1391 static_cast<uint32_t>(blit_region.srcOffsets[1].z - blit_region.srcOffsets[0].z)};
1392 auto hazard = context->DetectHazard(*src_image, SYNC_TRANSFER_TRANSFER_READ, blit_region.srcSubresource,
1393 blit_region.srcOffsets[0], extent);
1394 if (hazard.hazard) {
locke-lunarga0003652020-03-10 11:38:51 -06001395 skip |= LogError(srcImage, string_SyncHazardVUID(hazard.hazard),
1396 "vkCmdBlitImage: Hazard %s for srcImage %s, region %" PRIu32, string_SyncHazard(hazard.hazard),
1397 report_data->FormatHandle(srcImage).c_str(), region);
locke-lunarga19c71d2020-03-02 18:17:04 -07001398 }
1399 }
1400
1401 if (dst_image) {
1402 VkExtent3D extent = {static_cast<uint32_t>(blit_region.dstOffsets[1].x - blit_region.dstOffsets[0].x),
1403 static_cast<uint32_t>(blit_region.dstOffsets[1].y - blit_region.dstOffsets[0].y),
1404 static_cast<uint32_t>(blit_region.dstOffsets[1].z - blit_region.dstOffsets[0].z)};
1405 auto hazard = context->DetectHazard(*dst_image, SYNC_TRANSFER_TRANSFER_WRITE, blit_region.dstSubresource,
1406 blit_region.dstOffsets[0], extent);
1407 if (hazard.hazard) {
locke-lunarga0003652020-03-10 11:38:51 -06001408 skip |= LogError(dstImage, string_SyncHazardVUID(hazard.hazard),
1409 "vkCmdBlitImage: Hazard %s for dstImage %s, region %" PRIu32, string_SyncHazard(hazard.hazard),
1410 report_data->FormatHandle(dstImage).c_str(), region);
locke-lunarga19c71d2020-03-02 18:17:04 -07001411 }
1412 if (skip) break;
1413 }
1414 }
1415
1416 return skip;
1417}
1418
1419void SyncValidator::PreCallRecordCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
1420 VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
1421 const VkImageBlit *pRegions, VkFilter filter) {
1422 auto *cb_access_context = GetAccessContext(commandBuffer);
1423 assert(cb_access_context);
1424 auto *context = cb_access_context->GetCurrentAccessContext();
1425 assert(context);
1426
1427 auto *src_image = Get<IMAGE_STATE>(srcImage);
locke-lunarga19c71d2020-03-02 18:17:04 -07001428 auto *dst_image = Get<IMAGE_STATE>(dstImage);
locke-lunarga19c71d2020-03-02 18:17:04 -07001429
1430 for (uint32_t region = 0; region < regionCount; region++) {
1431 const auto &blit_region = pRegions[region];
1432 if (src_image) {
1433 VkExtent3D extent = {static_cast<uint32_t>(blit_region.srcOffsets[1].x - blit_region.srcOffsets[0].x),
1434 static_cast<uint32_t>(blit_region.srcOffsets[1].y - blit_region.srcOffsets[0].y),
1435 static_cast<uint32_t>(blit_region.srcOffsets[1].z - blit_region.srcOffsets[0].z)};
John Zulauf5f13a792020-03-10 07:31:21 -06001436 context->UpdateAccessState(*src_image, SYNC_TRANSFER_TRANSFER_READ, blit_region.srcSubresource,
1437 blit_region.srcOffsets[0], extent, tag);
locke-lunarga19c71d2020-03-02 18:17:04 -07001438 }
1439 if (dst_image) {
1440 VkExtent3D extent = {static_cast<uint32_t>(blit_region.dstOffsets[1].x - blit_region.dstOffsets[0].x),
1441 static_cast<uint32_t>(blit_region.dstOffsets[1].y - blit_region.dstOffsets[0].y),
1442 static_cast<uint32_t>(blit_region.dstOffsets[1].z - blit_region.dstOffsets[0].z)};
John Zulauf5f13a792020-03-10 07:31:21 -06001443 context->UpdateAccessState(*dst_image, SYNC_TRANSFER_TRANSFER_WRITE, blit_region.dstSubresource,
1444 blit_region.dstOffsets[0], extent, tag);
locke-lunarga19c71d2020-03-02 18:17:04 -07001445 }
1446 }
1447}