blob: 17073701764b3bd1af637ad1596ff338f64effca [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 Zulauf5f13a792020-03-10 07:31:21 -0600154template <typename Detector>
155HazardResult AccessTrackerContext::DetectPreviousHazard(const VulkanTypedHandle &handle, const Detector &detector,
156 const ResourceAccessRange &range) const {
157 ResourceAccessRangeMap descent_map;
158 ResourceAccessState default_state; // When present, PreviousAccess will "infill"
159 ResolvePreviousAccess(handle, range, &descent_map, &default_state);
160
161 HazardResult hazard;
162 for (auto prev = descent_map.begin(); prev != descent_map.end() && !hazard.hazard; ++prev) {
163 hazard = detector.Detect(prev);
164 }
165 return hazard;
166}
167
John Zulauf3d84f1b2020-03-09 13:33:25 -0600168// A recursive range walker for hazard detection, first for the current context and the (DetectHazardRecur) to walk
169// the DAG of the contexts (for example subpasses)
170template <typename Detector>
171HazardResult AccessTrackerContext::DetectHazard(const VulkanTypedHandle &handle, const Detector &detector,
John Zulauf5f13a792020-03-10 07:31:21 -0600172 const ResourceAccessRange &range) const {
John Zulauf3d84f1b2020-03-09 13:33:25 -0600173 HazardResult hazard;
John Zulauf5f13a792020-03-10 07:31:21 -0600174
175 // Async checks don't require recursive lookups, as the async lists are exhaustive for the top-level context
176 // so we'll check these first
177 for (const auto &async_context : async_) {
178 hazard = async_context->DetectAsyncHazard(handle, detector, range);
179 if (hazard.hazard) return hazard;
180 }
181
182 const auto access_tracker = GetAccessTracker(handle);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600183 if (access_tracker) {
184 const auto &accesses = access_tracker->GetCurrentAccessMap();
185 const auto from = accesses.lower_bound(range);
186 if (from != accesses.end() && from->first.intersects(range)) {
John Zulauf3d84f1b2020-03-09 13:33:25 -0600187 const auto to = accesses.upper_bound(range);
188 ResourceAccessRange gap = {range.begin, range.begin};
189 for (auto pos = from; pos != to; ++pos) {
John Zulauf5f13a792020-03-10 07:31:21 -0600190 hazard = detector.Detect(pos);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600191 if (hazard.hazard) return hazard;
192
John Zulauf5f13a792020-03-10 07:31:21 -0600193 // make sure we don't go past range
John Zulauf3d84f1b2020-03-09 13:33:25 -0600194 auto upper_bound = std::min(range.end, pos->first.end);
John Zulauf5f13a792020-03-10 07:31:21 -0600195 gap.end = upper_bound;
196
197 // 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 -0600198 if (!gap.empty()) {
199 // Must recur on all gaps
John Zulauf5f13a792020-03-10 07:31:21 -0600200 hazard = DetectPreviousHazard(handle, detector, gap);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600201 if (hazard.hazard) return hazard;
202 }
203 gap.begin = upper_bound;
204 }
John Zulauf5f13a792020-03-10 07:31:21 -0600205 gap.end = range.end;
206 if (gap.non_empty()) {
207 hazard = DetectPreviousHazard(handle, detector, gap);
208 if (hazard.hazard) return hazard;
209 }
210 } else {
211 hazard = DetectPreviousHazard(handle, detector, range);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600212 }
John Zulauf5f13a792020-03-10 07:31:21 -0600213 } else {
214 hazard = DetectPreviousHazard(handle, detector, range);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600215 }
216
217 return hazard;
218}
219
220// A non recursive range walker for the asynchronous contexts (those we have no barriers with)
221template <typename Detector>
222HazardResult AccessTrackerContext::DetectAsyncHazard(const VulkanTypedHandle &handle, const Detector &detector,
223 const ResourceAccessRange &range) const {
224 const auto access_tracker = GetAccessTracker(handle);
225 HazardResult hazard;
226 if (access_tracker) {
227 auto accesses = access_tracker->GetCurrentAccessMap();
228 const auto from = accesses.lower_bound(range);
229 const auto to = accesses.upper_bound(range);
230 for (auto pos = from; pos != to; ++pos) {
231 hazard = detector.DetectAsync(pos);
232 if (hazard.hazard) break;
233 }
234 }
235 return hazard;
236}
237
John Zulauf5f13a792020-03-10 07:31:21 -0600238void AccessTrackerContext::ResolveTrackBack(const VulkanTypedHandle &handle, const ResourceAccessRange &range,
239 const AccessTrackerContext::TrackBack &track_back, ResourceAccessRangeMap *descent_map,
240 const ResourceAccessState *infill_state) const {
241 const auto *access_tracker = GetAccessTracker(handle);
242 if (access_tracker) {
243 sparse_container::parallel_iterator<ResourceAccessRangeMap, const ResourceAccessRangeMap> current(
244 *descent_map, access_tracker->GetCurrentAccessMap(), range.begin);
245 while (current->range.non_empty()) {
246 if (current->pos_B->valid) {
247 auto access_with_barrier = current->pos_B->lower_bound->second;
248 access_with_barrier.ApplyBarrier(track_back.barrier);
249 if (current->pos_A->valid) {
250 // split A to match B's range
251 const auto &dst_range = current->pos_A->lower_bound->first;
252 const auto split_range = current->range & dst_range;
253 auto dst_pos = current->pos_A->lower_bound;
John Zulauf3d84f1b2020-03-09 13:33:25 -0600254
John Zulauf5f13a792020-03-10 07:31:21 -0600255 if (split_range.begin != dst_range.begin) {
256 dst_pos = descent_map->split(dst_pos, split_range.begin, sparse_container::split_op_keep_both());
257 ++dst_pos;
258 }
259 if (split_range.end != dst_range.end) {
260 dst_pos = descent_map->split(dst_pos, split_range.end, sparse_container::split_op_keep_both());
261 }
262 if (split_range != dst_range) {
263 current.invalidate_A(); // Update the parallel iterator to point at the correct segment after split(s)
264 }
265 current->pos_A->lower_bound->second.Resolve(access_with_barrier);
266 } else {
267 descent_map->insert(current->pos_A->lower_bound, std::make_pair(current->range, access_with_barrier));
268 current.invalidate_A(); // Update the parallel iterator to point at the correct segment after split(s)
269 }
270 } else {
271 // we have to descend to fill this gap
272 track_back.context->ResolvePreviousAccess(handle, range, descent_map, infill_state);
273 current.invalidate_A(); // Update the parallel iterator to point at the correct segment after recursion.
274 if (!current->pos_A->valid && infill_state) {
275 // If we didn't find anything in the previous range, we infill with default to prevent repeating
276 // a fruitless search
277 descent_map->insert(current->pos_A->lower_bound, std::make_pair(current->range, *infill_state));
278 current.invalidate_A(); // Update the parallel iterator to point at the correct segment after insert
279 }
280 }
281 ++current;
282 }
John Zulauf3d84f1b2020-03-09 13:33:25 -0600283 }
John Zulauf3d84f1b2020-03-09 13:33:25 -0600284}
285
John Zulauf5f13a792020-03-10 07:31:21 -0600286void AccessTrackerContext::ResolvePreviousAccess(const VulkanTypedHandle &handle, const ResourceAccessRange &range,
287 ResourceAccessRangeMap *descent_map,
288 const ResourceAccessState *infill_state) const {
289 if ((prev_.size() == 0) && (external_.context == nullptr)) {
290 if (range.non_empty() && infill_state) {
291 descent_map->insert(std::make_pair(range, *infill_state));
292 }
293 } else {
294 // Look for something to fill the gap further along.
295 for (const auto &prev_dep : prev_) {
296 ResolveTrackBack(handle, range, prev_dep, descent_map, infill_state);
297 }
298
299 if (external_.context) {
300 ResolveTrackBack(handle, range, external_, descent_map, infill_state);
301 }
302 }
John Zulauf3d84f1b2020-03-09 13:33:25 -0600303}
304
305class HazardDetector {
306 SyncStageAccessIndex usage_index_;
307
308 public:
John Zulauf5f13a792020-03-10 07:31:21 -0600309 HazardResult Detect(const ResourceAccessRangeMap::const_iterator &pos) const { return pos->second.DetectHazard(usage_index_); }
John Zulauf3d84f1b2020-03-09 13:33:25 -0600310 HazardResult DetectAsync(const ResourceAccessRangeMap::const_iterator &pos) const {
311 return pos->second.DetectAsyncHazard(usage_index_);
312 }
313 HazardDetector(SyncStageAccessIndex usage) : usage_index_(usage) {}
314};
315
316HazardResult AccessTrackerContext::DetectHazard(const VulkanTypedHandle &handle, SyncStageAccessIndex usage_index,
317 const ResourceAccessRange &range) const {
318 HazardDetector detector(usage_index);
319 return DetectHazard(handle, detector, range);
320}
321
322void CommandBufferAccessContext::BeginRenderPass(const RENDER_PASS_STATE &rp_state) {
323 // Create an access context for the first subpass and add it to the command buffers collection
324 render_pass_contexts_.emplace_back(queue_flags_, &rp_state.subpass_dependencies, &cb_tracker_context_);
325 current_renderpass_context_ = &render_pass_contexts_.back();
326 current_context_ = &current_renderpass_context_->CurrentContext();
327}
328
329void CommandBufferAccessContext::NextRenderPass(const RENDER_PASS_STATE &rp_state) {
330 assert(current_renderpass_context_);
331 current_renderpass_context_->NextSubpass(queue_flags_, &cb_tracker_context_);
332 current_context_ = &current_renderpass_context_->CurrentContext();
333}
334
335HazardResult AccessTrackerContext::DetectHazard(const IMAGE_STATE &image, SyncStageAccessIndex current_usage,
336 const VkImageSubresourceLayers &subresource, const VkOffset3D &offset,
337 const VkExtent3D &extent) const {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700338 // TODO: replace the encoder/generator with offset3D/extent3D aware versions
339 VkImageSubresourceRange subresource_range = {subresource.aspectMask, subresource.mipLevel, 1, subresource.baseArrayLayer,
340 subresource.layerCount};
locke-lunarg1dbbb9e2020-02-28 22:43:53 -0700341 VkExtent3D subresource_extent = GetImageSubresourceExtent(&image, &subresource);
342 subresource_adapter::OffsetRangeEncoder encoder(image.full_range, subresource_extent);
343 subresource_adapter::OffsetRangeGenerator range_gen(encoder, subresource_range, offset, extent);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600344 VulkanTypedHandle image_handle(image.image, kVulkanObjectTypeImage);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700345 for (; range_gen->non_empty(); ++range_gen) {
John Zulauf3d84f1b2020-03-09 13:33:25 -0600346 HazardResult hazard = DetectHazard(image_handle, current_usage, *range_gen);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700347 if (hazard.hazard) return hazard;
348 }
349 return HazardResult();
John Zulauf9cb530d2019-09-30 14:14:10 -0600350}
351
John Zulauf3d84f1b2020-03-09 13:33:25 -0600352class BarrierHazardDetector {
353 public:
354 BarrierHazardDetector(SyncStageAccessIndex usage_index, VkPipelineStageFlags src_exec_scope,
355 SyncStageAccessFlags src_access_scope)
356 : usage_index_(usage_index), src_exec_scope_(src_exec_scope), src_access_scope_(src_access_scope) {}
357
John Zulauf5f13a792020-03-10 07:31:21 -0600358 HazardResult Detect(const ResourceAccessRangeMap::const_iterator &pos) const {
359 return pos->second.DetectBarrierHazard(usage_index_, src_exec_scope_, src_access_scope_);
John Zulauf0cb5be22020-01-23 12:18:22 -0700360 }
John Zulauf3d84f1b2020-03-09 13:33:25 -0600361 HazardResult DetectAsync(const ResourceAccessRangeMap::const_iterator &pos) const {
362 // Async barrier hazard detection can use the same path as the usage index is not IsRead, but is IsWrite
363 return pos->second.DetectAsyncHazard(usage_index_);
364 }
365
366 private:
367 SyncStageAccessIndex usage_index_;
368 VkPipelineStageFlags src_exec_scope_;
369 SyncStageAccessFlags src_access_scope_;
370};
371
372HazardResult AccessTrackerContext::DetectBarrierHazard(const VulkanTypedHandle &handle, SyncStageAccessIndex current_usage,
373 VkPipelineStageFlags src_exec_scope, SyncStageAccessFlags src_access_scope,
374 const ResourceAccessRange &range) const {
375 BarrierHazardDetector detector(current_usage, src_exec_scope, src_access_scope);
376 return DetectHazard(handle, detector, range);
John Zulauf0cb5be22020-01-23 12:18:22 -0700377}
378
John Zulauf3d84f1b2020-03-09 13:33:25 -0600379HazardResult DetectImageBarrierHazard(const AccessTrackerContext &context, const IMAGE_STATE &image,
John Zulauf36bcf6a2020-02-03 15:12:52 -0700380 VkPipelineStageFlags src_exec_scope, SyncStageAccessFlags src_stage_accesses,
John Zulauf0cb5be22020-01-23 12:18:22 -0700381 const VkImageMemoryBarrier &barrier) {
John Zulauf0cb5be22020-01-23 12:18:22 -0700382 auto subresource_range = NormalizeSubresourceRange(image.createInfo, barrier.subresourceRange);
locke-lunarg1dbbb9e2020-02-28 22:43:53 -0700383 VkImageSubresourceLayers subresource_layers = {subresource_range.aspectMask, 0, subresource_range.baseArrayLayer,
384 subresource_range.layerCount};
John Zulauf3d84f1b2020-03-09 13:33:25 -0600385 const VulkanTypedHandle image_handle(image.image, kVulkanObjectTypeImage);
John Zulauf36bcf6a2020-02-03 15:12:52 -0700386 const auto src_access_scope = SyncStageAccess::AccessScope(src_stage_accesses, barrier.srcAccessMask);
locke-lunarg1dbbb9e2020-02-28 22:43:53 -0700387 for (uint32_t mip_index = subresource_range.baseMipLevel; mip_index < subresource_range.levelCount; mip_index++) {
388 subresource_layers.mipLevel = mip_index;
389 VkExtent3D subresource_extent = GetImageSubresourceExtent(&image, &subresource_layers);
390 subresource_adapter::OffsetRangeEncoder encoder(image.full_range, subresource_extent);
391 subresource_adapter::OffsetRangeGenerator range_gen(encoder, subresource_range, {0, 0}, subresource_extent);
392 for (; range_gen->non_empty(); ++range_gen) {
393 HazardResult hazard = context.DetectBarrierHazard(image_handle, SyncStageAccessIndex::SYNC_IMAGE_LAYOUT_TRANSITION,
394 src_exec_scope, src_access_scope, *range_gen);
395 if (hazard.hazard) return hazard;
396 }
John Zulauf0cb5be22020-01-23 12:18:22 -0700397 }
398 return HazardResult();
399}
400
John Zulauf9cb530d2019-09-30 14:14:10 -0600401template <typename Flags, typename Map>
402SyncStageAccessFlags AccessScopeImpl(Flags flag_mask, const Map &map) {
403 SyncStageAccessFlags scope = 0;
404 for (const auto &bit_scope : map) {
405 if (flag_mask < bit_scope.first) break;
406
407 if (flag_mask & bit_scope.first) {
408 scope |= bit_scope.second;
409 }
410 }
411 return scope;
412}
413
414SyncStageAccessFlags SyncStageAccess::AccessScopeByStage(VkPipelineStageFlags stages) {
415 return AccessScopeImpl(stages, syncStageAccessMaskByStageBit);
416}
417
418SyncStageAccessFlags SyncStageAccess::AccessScopeByAccess(VkAccessFlags accesses) {
419 return AccessScopeImpl(accesses, syncStageAccessMaskByAccessBit);
420}
421
422// Getting from stage mask and access mask to stage/acess masks is something we need to be good at...
423SyncStageAccessFlags SyncStageAccess::AccessScope(VkPipelineStageFlags stages, VkAccessFlags accesses) {
John Zulauf5f13a792020-03-10 07:31:21 -0600424 // The access scope is the intersection of all stage/access types possible for the enabled stages and the enables
425 // accesses (after doing a couple factoring of common terms the union of stage/access intersections is the intersections
426 // 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 -0600427 return AccessScopeByStage(stages) & AccessScopeByAccess(accesses);
428}
429
430template <typename Action>
John Zulauf5c5e88d2019-12-26 11:22:02 -0700431void UpdateMemoryAccessState(ResourceAccessRangeMap *accesses, const ResourceAccessRange &range, const Action &action) {
John Zulauf9cb530d2019-09-30 14:14:10 -0600432 // TODO -- region/mem-range accuracte update
433 auto pos = accesses->lower_bound(range);
434 if (pos == accesses->end() || !pos->first.intersects(range)) {
435 // The range is empty, fill it with a default value.
436 pos = action.Infill(accesses, pos, range);
437 } else if (range.begin < pos->first.begin) {
438 // Leading empty space, infill
John Zulauf5c5e88d2019-12-26 11:22:02 -0700439 pos = action.Infill(accesses, pos, ResourceAccessRange(range.begin, pos->first.begin));
John Zulauf9cb530d2019-09-30 14:14:10 -0600440 } else if (pos->first.begin < range.begin) {
441 // Trim the beginning if needed
442 pos = accesses->split(pos, range.begin, sparse_container::split_op_keep_both());
443 ++pos;
444 }
445
446 const auto the_end = accesses->end();
447 while ((pos != the_end) && pos->first.intersects(range)) {
448 if (pos->first.end > range.end) {
449 pos = accesses->split(pos, range.end, sparse_container::split_op_keep_both());
450 }
451
452 pos = action(accesses, pos);
453 if (pos == the_end) break;
454
455 auto next = pos;
456 ++next;
457 if ((pos->first.end < range.end) && (next != the_end) && !next->first.is_subsequent_to(pos->first)) {
458 // Need to infill if next is disjoint
459 VkDeviceSize limit = (next == the_end) ? range.end : std::min(range.end, next->first.begin);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700460 ResourceAccessRange new_range(pos->first.end, limit);
John Zulauf9cb530d2019-09-30 14:14:10 -0600461 next = action.Infill(accesses, next, new_range);
462 }
463 pos = next;
464 }
465}
466
467struct UpdateMemoryAccessStateFunctor {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700468 using Iterator = ResourceAccessRangeMap::iterator;
469 Iterator Infill(ResourceAccessRangeMap *accesses, Iterator pos, ResourceAccessRange range) const {
John Zulauf5f13a792020-03-10 07:31:21 -0600470 // this is only called on gaps, and never returns a gap.
471 ResourceAccessState default_state;
472 context.ResolvePreviousAccess(handle, range, accesses, &default_state);
473 return accesses->lower_bound(range);
John Zulauf9cb530d2019-09-30 14:14:10 -0600474 }
John Zulauf5f13a792020-03-10 07:31:21 -0600475
John Zulauf5c5e88d2019-12-26 11:22:02 -0700476 Iterator operator()(ResourceAccessRangeMap *accesses, Iterator pos) const {
John Zulauf9cb530d2019-09-30 14:14:10 -0600477 auto &access_state = pos->second;
478 access_state.Update(usage, tag);
479 return pos;
480 }
481
John Zulauf5f13a792020-03-10 07:31:21 -0600482 UpdateMemoryAccessStateFunctor(const VulkanTypedHandle &handle_, const AccessTrackerContext &context_,
483 SyncStageAccessIndex usage_, const ResourceUsageTag &tag_)
484 : handle(handle_), context(context_), usage(usage_), tag(tag_) {}
485 const VulkanTypedHandle handle;
486 const AccessTrackerContext &context;
John Zulauf9cb530d2019-09-30 14:14:10 -0600487 SyncStageAccessIndex usage;
488 const ResourceUsageTag &tag;
489};
490
491struct ApplyMemoryAccessBarrierFunctor {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700492 using Iterator = ResourceAccessRangeMap::iterator;
493 inline Iterator Infill(ResourceAccessRangeMap *accesses, Iterator pos, ResourceAccessRange range) const { return pos; }
John Zulauf9cb530d2019-09-30 14:14:10 -0600494
John Zulauf5c5e88d2019-12-26 11:22:02 -0700495 Iterator operator()(ResourceAccessRangeMap *accesses, Iterator pos) const {
John Zulauf9cb530d2019-09-30 14:14:10 -0600496 auto &access_state = pos->second;
John Zulauf36bcf6a2020-02-03 15:12:52 -0700497 access_state.ApplyMemoryAccessBarrier(src_exec_scope, src_access_scope, dst_exec_scope, dst_access_scope);
John Zulauf9cb530d2019-09-30 14:14:10 -0600498 return pos;
499 }
500
John Zulauf36bcf6a2020-02-03 15:12:52 -0700501 ApplyMemoryAccessBarrierFunctor(VkPipelineStageFlags src_exec_scope_, SyncStageAccessFlags src_access_scope_,
502 VkPipelineStageFlags dst_exec_scope_, SyncStageAccessFlags dst_access_scope_)
503 : src_exec_scope(src_exec_scope_),
504 src_access_scope(src_access_scope_),
505 dst_exec_scope(dst_exec_scope_),
506 dst_access_scope(dst_access_scope_) {}
John Zulauf9cb530d2019-09-30 14:14:10 -0600507
John Zulauf36bcf6a2020-02-03 15:12:52 -0700508 VkPipelineStageFlags src_exec_scope;
509 SyncStageAccessFlags src_access_scope;
510 VkPipelineStageFlags dst_exec_scope;
511 SyncStageAccessFlags dst_access_scope;
John Zulauf9cb530d2019-09-30 14:14:10 -0600512};
513
514struct ApplyGlobalBarrierFunctor {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700515 using Iterator = ResourceAccessRangeMap::iterator;
516 inline Iterator Infill(ResourceAccessRangeMap *accesses, Iterator pos, ResourceAccessRange range) const { return pos; }
John Zulauf9cb530d2019-09-30 14:14:10 -0600517
John Zulauf5c5e88d2019-12-26 11:22:02 -0700518 Iterator operator()(ResourceAccessRangeMap *accesses, Iterator pos) const {
John Zulauf9cb530d2019-09-30 14:14:10 -0600519 auto &access_state = pos->second;
John Zulauf36bcf6a2020-02-03 15:12:52 -0700520 access_state.ApplyExecutionBarrier(src_exec_scope, dst_exec_scope);
John Zulauf9cb530d2019-09-30 14:14:10 -0600521
522 for (const auto &functor : barrier_functor) {
523 functor(accesses, pos);
524 }
525 return pos;
526 }
527
John Zulauf36bcf6a2020-02-03 15:12:52 -0700528 ApplyGlobalBarrierFunctor(VkPipelineStageFlags src_exec_scope, VkPipelineStageFlags dst_exec_scope,
529 SyncStageAccessFlags src_stage_accesses, SyncStageAccessFlags dst_stage_accesses,
John Zulauf9cb530d2019-09-30 14:14:10 -0600530 uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers)
John Zulauf36bcf6a2020-02-03 15:12:52 -0700531 : src_exec_scope(src_exec_scope), dst_exec_scope(dst_exec_scope) {
John Zulauf9cb530d2019-09-30 14:14:10 -0600532 // Don't want to create this per tracked item, but don't want to loop through all tracked items per barrier...
533 barrier_functor.reserve(memoryBarrierCount);
534 for (uint32_t barrier_index = 0; barrier_index < memoryBarrierCount; barrier_index++) {
535 const auto &barrier = pMemoryBarriers[barrier_index];
John Zulauf36bcf6a2020-02-03 15:12:52 -0700536 barrier_functor.emplace_back(src_exec_scope, SyncStageAccess::AccessScope(src_stage_accesses, barrier.srcAccessMask),
537 dst_exec_scope, SyncStageAccess::AccessScope(dst_stage_accesses, barrier.dstAccessMask));
John Zulauf9cb530d2019-09-30 14:14:10 -0600538 }
539 }
540
John Zulauf36bcf6a2020-02-03 15:12:52 -0700541 const VkPipelineStageFlags src_exec_scope;
542 const VkPipelineStageFlags dst_exec_scope;
John Zulauf9cb530d2019-09-30 14:14:10 -0600543 std::vector<ApplyMemoryAccessBarrierFunctor> barrier_functor;
544};
545
John Zulauf3d84f1b2020-03-09 13:33:25 -0600546void AccessTrackerContext::UpdateAccessState(const VulkanTypedHandle &handle, SyncStageAccessIndex current_usage,
547 const ResourceAccessRange &range, const ResourceUsageTag &tag) {
John Zulauf5f13a792020-03-10 07:31:21 -0600548 UpdateMemoryAccessStateFunctor action(handle, *this, current_usage, tag);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600549 auto *tracker = GetAccessTracker(handle);
550 assert(tracker);
John Zulauf5f13a792020-03-10 07:31:21 -0600551 UpdateMemoryAccessState(&tracker->GetCurrentAccessMap(), range, action);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600552}
553
John Zulauf5f13a792020-03-10 07:31:21 -0600554void AccessTrackerContext::UpdateAccessState(const IMAGE_STATE &image, SyncStageAccessIndex current_usage,
555 const VkImageSubresourceLayers &subresource, const VkOffset3D &offset,
556 const VkExtent3D &extent, const ResourceUsageTag &tag) {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700557 // TODO: replace the encoder/generator with offset3D aware versions
558 VkImageSubresourceRange subresource_range = {subresource.aspectMask, subresource.mipLevel, 1, subresource.baseArrayLayer,
559 subresource.layerCount};
locke-lunarg1dbbb9e2020-02-28 22:43:53 -0700560 VkExtent3D subresource_extent = GetImageSubresourceExtent(&image, &subresource);
561 subresource_adapter::OffsetRangeEncoder encoder(image.full_range, subresource_extent);
562 subresource_adapter::OffsetRangeGenerator range_gen(encoder, subresource_range, offset, extent);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700563
John Zulauf3d84f1b2020-03-09 13:33:25 -0600564 const VulkanTypedHandle handle(image.image, kVulkanObjectTypeImage);
565 auto *tracker = GetAccessTracker(handle);
566 assert(tracker);
John Zulauf5f13a792020-03-10 07:31:21 -0600567
568 UpdateMemoryAccessStateFunctor action(handle, *this, current_usage, tag);
569 for (; range_gen->non_empty(); ++range_gen) {
570 UpdateMemoryAccessState(&tracker->GetCurrentAccessMap(), *range_gen, action);
571 }
John Zulauf3d84f1b2020-03-09 13:33:25 -0600572}
573
574SyncBarrier::SyncBarrier(VkQueueFlags queue_flags, const VkSubpassDependency2 &barrier) {
575 const auto src_stage_mask = ExpandPipelineStages(queue_flags, barrier.srcStageMask);
576 src_exec_scope = WithEarlierPipelineStages(src_stage_mask);
577 src_access_scope = SyncStageAccess::AccessScope(src_stage_mask, barrier.srcAccessMask);
578 const auto dst_stage_mask = ExpandPipelineStages(queue_flags, barrier.dstStageMask);
579 dst_exec_scope = WithLaterPipelineStages(dst_stage_mask);
580 dst_access_scope = SyncStageAccess::AccessScope(dst_stage_mask, barrier.dstAccessMask);
581}
582
583void ResourceAccessState::ApplyBarrier(const SyncBarrier &barrier) {
584 ApplyExecutionBarrier(barrier.src_exec_scope, barrier.dst_exec_scope);
585 ApplyMemoryAccessBarrier(barrier.src_exec_scope, barrier.src_access_scope, barrier.dst_exec_scope, barrier.dst_access_scope);
586}
587
588ResourceAccessState ResourceAccessState::ApplyBarrierStack(const ResourceAccessState &that, const SyncBarrierStack &barrier_stack) {
589 ResourceAccessState copy = that;
590 for (auto barrier = barrier_stack.begin(); barrier != barrier_stack.end(); ++barrier) {
591 assert(*barrier);
592 copy.ApplyBarrier(*(*barrier));
593 }
594 return copy;
595}
596
597HazardResult ResourceAccessState::DetectHazard(SyncStageAccessIndex usage_index, SyncBarrierStack *barrier_stack) const {
598 if (barrier_stack) {
599 return ApplyBarrierStack(*this, *barrier_stack).DetectHazard(usage_index);
600 }
601 return DetectHazard(usage_index);
602}
603
John Zulauf9cb530d2019-09-30 14:14:10 -0600604HazardResult ResourceAccessState::DetectHazard(SyncStageAccessIndex usage_index) const {
605 HazardResult hazard;
606 auto usage = FlagBit(usage_index);
607 if (IsRead(usage)) {
608 if (IsWriteHazard(usage)) {
609 hazard.Set(READ_AFTER_WRITE, write_tag);
610 }
611 } else {
612 // Assume write
613 // TODO determine what to do with READ-WRITE usage states if any
614 // Write-After-Write check -- if we have a previous write to test against
615 if (last_write && IsWriteHazard(usage)) {
616 hazard.Set(WRITE_AFTER_WRITE, write_tag);
617 } else {
618 // Only look for casus belli for WAR
619 const auto usage_stage = PipelineStageBit(usage_index);
620 for (uint32_t read_index = 0; read_index < last_read_count; read_index++) {
621 if (IsReadHazard(usage_stage, last_reads[read_index])) {
622 hazard.Set(WRITE_AFTER_READ, last_reads[read_index].tag);
623 break;
624 }
625 }
626 }
627 }
628 return hazard;
629}
630
John Zulauf2f952d22020-02-10 11:34:51 -0700631// Asynchronous Hazards occur between subpasses with no connection through the DAG
John Zulauf3d84f1b2020-03-09 13:33:25 -0600632HazardResult ResourceAccessState::DetectAsyncHazard(SyncStageAccessIndex usage_index) const {
John Zulauf2f952d22020-02-10 11:34:51 -0700633 HazardResult hazard;
634 auto usage = FlagBit(usage_index);
635 if (IsRead(usage)) {
636 if (last_write != 0) {
637 hazard.Set(READ_RACING_WRITE, write_tag);
638 }
639 } else {
640 if (last_write != 0) {
641 hazard.Set(WRITE_RACING_WRITE, write_tag);
642 } else if (last_read_count > 0) {
643 hazard.Set(WRITE_RACING_READ, last_reads[0].tag);
644 }
645 }
646 return hazard;
647}
648
John Zulauf36bcf6a2020-02-03 15:12:52 -0700649HazardResult ResourceAccessState::DetectBarrierHazard(SyncStageAccessIndex usage_index, VkPipelineStageFlags src_exec_scope,
John Zulauf3d84f1b2020-03-09 13:33:25 -0600650 SyncStageAccessFlags src_access_scope,
651 SyncBarrierStack *barrier_stack) const {
652 if (barrier_stack) {
653 return ApplyBarrierStack(*this, *barrier_stack).DetectBarrierHazard(usage_index, src_exec_scope, src_access_scope);
654 }
655 return DetectBarrierHazard(usage_index, src_exec_scope, src_access_scope);
656}
657
658HazardResult ResourceAccessState::DetectBarrierHazard(SyncStageAccessIndex usage_index, VkPipelineStageFlags src_exec_scope,
John Zulauf36bcf6a2020-02-03 15:12:52 -0700659 SyncStageAccessFlags src_access_scope) const {
John Zulauf0cb5be22020-01-23 12:18:22 -0700660 // Only supporting image layout transitions for now
661 assert(usage_index == SyncStageAccessIndex::SYNC_IMAGE_LAYOUT_TRANSITION);
662 HazardResult hazard;
663 if (last_write) {
664 // If the previous write is *not* in the 1st access scope
665 // *AND* the current barrier is not in the dependency chain
666 // *AND* the there is no prior memory barrier for the previous write in the dependency chain
667 // then the barrier access is unsafe (R/W after W)
John Zulauf36bcf6a2020-02-03 15:12:52 -0700668 if (((last_write & src_access_scope) == 0) && ((src_exec_scope & write_dependency_chain) == 0) && (write_barriers == 0)) {
John Zulauf0cb5be22020-01-23 12:18:22 -0700669 // TODO: Do we need a difference hazard name for this?
670 hazard.Set(WRITE_AFTER_WRITE, write_tag);
671 }
672 } else {
673 // Look at the reads
674 for (uint32_t read_index = 0; read_index < last_read_count; read_index++) {
John Zulauf36bcf6a2020-02-03 15:12:52 -0700675 const auto &read_access = last_reads[read_index];
676 // If the read stage is not in the src sync sync
677 // *AND* not execution chained with an existing sync barrier (that's the or)
678 // then the barrier access is unsafe (R/W after R)
679 if ((src_exec_scope & (read_access.stage | read_access.barriers)) == 0) {
680 hazard.Set(WRITE_AFTER_READ, read_access.tag);
John Zulauf0cb5be22020-01-23 12:18:22 -0700681 break;
682 }
683 }
684 }
685 return hazard;
686}
687
John Zulauf5f13a792020-03-10 07:31:21 -0600688// The logic behind resolves is the same as update, we assume that earlier hazards have be reported, and that no
689// tranistive hazard can exists with a hazard between the earlier operations. Yes, an early hazard can mask that another
690// exists, but if you fix *that* hazard it either fixes or unmasks the subsequent ones.
691void ResourceAccessState::Resolve(const ResourceAccessState &other) {
692 if (write_tag.IsBefore(other.write_tag)) {
693 // If this is a later write, we've reported any exsiting hazard, and we can just overwrite as the more recent operation
694 *this = other;
695 } else if (!other.write_tag.IsBefore(write_tag)) {
696 // This is the *equals* case for write operations, we merged the write barriers and the read state (but without the
697 // dependency chaining logic or any stage expansion)
698 write_barriers |= other.write_barriers;
699
700 // Merge that read states
701 for (uint32_t other_read_index = 0; other_read_index < other.last_read_count; other_read_index++) {
702 auto &other_read = other.last_reads[other_read_index];
703 if (last_read_stages & other_read.stage) {
704 // Merge in the barriers for read stages that exist in *both* this and other
705 // TODO: This is N^2 with stages... perhaps the ReadStates should be by stage index.
706 for (uint32_t my_read_index = 0; my_read_index < last_read_count; my_read_index++) {
707 auto &my_read = last_reads[my_read_index];
708 if (other_read.stage == my_read.stage) {
709 if (my_read.tag.IsBefore(other_read.tag)) {
710 my_read.tag = other_read.tag;
711 }
712 my_read.barriers |= other_read.barriers;
713 break;
714 }
715 }
716 } else {
717 // The other read stage doesn't exist in this, so add it.
718 last_reads[last_read_count] = other_read;
719 last_read_count++;
720 last_read_stages |= other_read.stage;
721 }
722 }
723 } // the else clause would be that other write is before this write... in which case we supercede the other state and ignore
724 // it.
725}
726
John Zulauf9cb530d2019-09-30 14:14:10 -0600727void ResourceAccessState::Update(SyncStageAccessIndex usage_index, const ResourceUsageTag &tag) {
728 // Move this logic in the ResourceStateTracker as methods, thereof (or we'll repeat it for every flavor of resource...
729 const auto usage_bit = FlagBit(usage_index);
730 if (IsRead(usage_index)) {
731 // Mulitple outstanding reads may be of interest and do dependency chains independently
732 // However, for purposes of barrier tracking, only one read per pipeline stage matters
733 const auto usage_stage = PipelineStageBit(usage_index);
734 if (usage_stage & last_read_stages) {
735 for (uint32_t read_index = 0; read_index < last_read_count; read_index++) {
736 ReadState &access = last_reads[read_index];
737 if (access.stage == usage_stage) {
738 access.barriers = 0;
739 access.tag = tag;
740 break;
741 }
742 }
743 } else {
744 // We don't have this stage in the list yet...
745 assert(last_read_count < last_reads.size());
746 ReadState &access = last_reads[last_read_count++];
747 access.stage = usage_stage;
748 access.barriers = 0;
749 access.tag = tag;
750 last_read_stages |= usage_stage;
751 }
752 } else {
753 // Assume write
754 // TODO determine what to do with READ-WRITE operations if any
755 // Clobber last read and both sets of barriers... because all we have is DANGER, DANGER, WILL ROBINSON!!!
756 // if the last_reads/last_write were unsafe, we've reported them,
757 // in either case the prior access is irrelevant, we can overwrite them as *this* write is now after them
758 last_read_count = 0;
759 last_read_stages = 0;
760
761 write_barriers = 0;
762 write_dependency_chain = 0;
763 write_tag = tag;
764 last_write = usage_bit;
765 }
766}
John Zulauf5f13a792020-03-10 07:31:21 -0600767
John Zulauf9cb530d2019-09-30 14:14:10 -0600768void ResourceAccessState::ApplyExecutionBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask) {
769 // Execution Barriers only protect read operations
770 for (uint32_t read_index = 0; read_index < last_read_count; read_index++) {
771 ReadState &access = last_reads[read_index];
772 // The | implements the "dependency chain" logic for this access, as the barriers field stores the second sync scope
773 if (srcStageMask & (access.stage | access.barriers)) {
774 access.barriers |= dstStageMask;
775 }
776 }
777 if (write_dependency_chain & srcStageMask) write_dependency_chain |= dstStageMask;
778}
779
John Zulauf36bcf6a2020-02-03 15:12:52 -0700780void ResourceAccessState::ApplyMemoryAccessBarrier(VkPipelineStageFlags src_exec_scope, SyncStageAccessFlags src_access_scope,
781 VkPipelineStageFlags dst_exec_scope, SyncStageAccessFlags dst_access_scope) {
John Zulauf9cb530d2019-09-30 14:14:10 -0600782 // Assuming we've applied the execution side of this barrier, we update just the write
783 // The || implements the "dependency chain" logic for this barrier
John Zulauf36bcf6a2020-02-03 15:12:52 -0700784 if ((src_access_scope & last_write) || (write_dependency_chain & src_exec_scope)) {
785 write_barriers |= dst_access_scope;
786 write_dependency_chain |= dst_exec_scope;
John Zulauf9cb530d2019-09-30 14:14:10 -0600787 }
788}
789
790void SyncValidator::ResetCommandBuffer(VkCommandBuffer command_buffer) {
John Zulauf3d84f1b2020-03-09 13:33:25 -0600791 auto *access_context = GetAccessContextNoInsert(command_buffer);
792 if (access_context) {
793 access_context->Reset();
John Zulauf9cb530d2019-09-30 14:14:10 -0600794 }
795}
796
John Zulauf3d84f1b2020-03-09 13:33:25 -0600797void SyncValidator::ApplyGlobalBarriers(AccessTrackerContext *context, VkPipelineStageFlags srcStageMask,
John Zulauf36bcf6a2020-02-03 15:12:52 -0700798 VkPipelineStageFlags dstStageMask, SyncStageAccessFlags src_access_scope,
799 SyncStageAccessFlags dst_access_scope, uint32_t memoryBarrierCount,
John Zulauf9cb530d2019-09-30 14:14:10 -0600800 const VkMemoryBarrier *pMemoryBarriers) {
801 // TODO: Implement this better (maybe some delayed/on-demand integration).
John Zulauf36bcf6a2020-02-03 15:12:52 -0700802 ApplyGlobalBarrierFunctor barriers_functor(srcStageMask, dstStageMask, src_access_scope, dst_access_scope, memoryBarrierCount,
John Zulauf9cb530d2019-09-30 14:14:10 -0600803 pMemoryBarriers);
John Zulauf5f13a792020-03-10 07:31:21 -0600804 // Note: Barriers do *not* cross context boundaries, applying to accessess within.... (at least for renderpass subpasses
John Zulauf3d84f1b2020-03-09 13:33:25 -0600805 for (auto &handle_tracker_pair : context->GetAccessTrackerMap()) {
806 UpdateMemoryAccessState(&handle_tracker_pair.second.GetCurrentAccessMap(), full_range, barriers_functor);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700807 }
John Zulauf9cb530d2019-09-30 14:14:10 -0600808}
809
John Zulauf3d84f1b2020-03-09 13:33:25 -0600810void SyncValidator::ApplyBufferBarriers(AccessTrackerContext *context, VkPipelineStageFlags src_exec_scope,
John Zulauf36bcf6a2020-02-03 15:12:52 -0700811 SyncStageAccessFlags src_stage_accesses, VkPipelineStageFlags dst_exec_scope,
812 SyncStageAccessFlags dst_stage_accesses, uint32_t barrier_count,
John Zulauf9cb530d2019-09-30 14:14:10 -0600813 const VkBufferMemoryBarrier *barriers) {
814 // TODO Implement this at subresource/memory_range accuracy
815 for (uint32_t index = 0; index < barrier_count; index++) {
816 const auto &barrier = barriers[index];
817 const auto *buffer = Get<BUFFER_STATE>(barrier.buffer);
818 if (!buffer) continue;
John Zulauf3d84f1b2020-03-09 13:33:25 -0600819 auto *tracker = context->GetAccessTracker(VulkanTypedHandle(buffer->binding.mem_state->mem, kVulkanObjectTypeDeviceMemory));
820 if (!tracker) continue;
John Zulauf5c5e88d2019-12-26 11:22:02 -0700821 ResourceAccessRange range = MakeMemoryAccessRange(*buffer, barrier.offset, barrier.size);
John Zulauf9cb530d2019-09-30 14:14:10 -0600822 UpdateMemoryAccessState(
John Zulauf3d84f1b2020-03-09 13:33:25 -0600823 &tracker->GetCurrentAccessMap(), range,
John Zulauf36bcf6a2020-02-03 15:12:52 -0700824 ApplyMemoryAccessBarrierFunctor(src_exec_scope, AccessScope(src_stage_accesses, barrier.srcAccessMask), dst_exec_scope,
825 AccessScope(dst_stage_accesses, barrier.dstAccessMask)));
John Zulauf9cb530d2019-09-30 14:14:10 -0600826 }
827}
828
John Zulauf3d84f1b2020-03-09 13:33:25 -0600829void SyncValidator::ApplyImageBarriers(AccessTrackerContext *context, VkPipelineStageFlags src_exec_scope,
John Zulauf36bcf6a2020-02-03 15:12:52 -0700830 SyncStageAccessFlags src_stage_accesses, VkPipelineStageFlags dst_exec_scope,
831 SyncStageAccessFlags dst_stage_accesses, uint32_t barrier_count,
John Zulauf5c5e88d2019-12-26 11:22:02 -0700832 const VkImageMemoryBarrier *barriers) {
833 for (uint32_t index = 0; index < barrier_count; index++) {
834 const auto &barrier = barriers[index];
835 const auto *image = Get<IMAGE_STATE>(barrier.image);
836 if (!image) continue;
John Zulauf3d84f1b2020-03-09 13:33:25 -0600837 auto tracker = context->GetAccessTrackerNoInsert(VulkanTypedHandle(barrier.image, kVulkanObjectTypeImage));
838 if (!tracker) continue;
839 auto *accesses = &tracker->GetCurrentAccessMap();
840
John Zulauf5c5e88d2019-12-26 11:22:02 -0700841 auto subresource_range = NormalizeSubresourceRange(image->createInfo, barrier.subresourceRange);
locke-lunarg1dbbb9e2020-02-28 22:43:53 -0700842 VkImageSubresourceLayers subresource_layers = {subresource_range.aspectMask, 0, subresource_range.baseArrayLayer,
843 subresource_range.layerCount};
844 for (uint32_t mip_index = subresource_range.baseMipLevel; mip_index < subresource_range.levelCount; mip_index++) {
845 subresource_layers.mipLevel = mip_index;
846 VkExtent3D subresource_extent = GetImageSubresourceExtent(image, &subresource_layers);
847 subresource_adapter::OffsetRangeEncoder encoder(image->full_range, subresource_extent);
848 subresource_adapter::OffsetRangeGenerator range_gen(encoder, subresource_range, {0, 0}, subresource_extent);
849
850 const ApplyMemoryAccessBarrierFunctor barrier_action(
851 src_exec_scope, AccessScope(src_stage_accesses, barrier.srcAccessMask), dst_exec_scope,
852 AccessScope(dst_stage_accesses, barrier.dstAccessMask));
853 for (; range_gen->non_empty(); ++range_gen) {
854 UpdateMemoryAccessState(accesses, *range_gen, barrier_action);
855 }
John Zulauf5c5e88d2019-12-26 11:22:02 -0700856 }
John Zulauf9cb530d2019-09-30 14:14:10 -0600857 }
John Zulauf9cb530d2019-09-30 14:14:10 -0600858}
859
860bool SyncValidator::PreCallValidateCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
861 uint32_t regionCount, const VkBufferCopy *pRegions) const {
862 bool skip = false;
John Zulauf3d84f1b2020-03-09 13:33:25 -0600863 const auto *cb_context = GetAccessContext(commandBuffer);
864 assert(cb_context);
865 if (!cb_context) return skip;
866 const auto *context = cb_context->GetCurrentAccessContext();
John Zulauf9cb530d2019-09-30 14:14:10 -0600867
John Zulauf3d84f1b2020-03-09 13:33:25 -0600868 // If we have no previous accesses, we have no hazards
869 // TODO: make this sub-resource capable
870 // TODO: make this general, and stuff it into templates/utility functions
871 const auto *src_buffer = Get<BUFFER_STATE>(srcBuffer);
872 const auto src_mem = (src_buffer && !src_buffer->sparse) ? src_buffer->binding.mem_state->mem : VK_NULL_HANDLE;
873 const auto *dst_buffer = Get<BUFFER_STATE>(dstBuffer);
874 const auto dst_mem = (dst_buffer && !dst_buffer->sparse) ? dst_buffer->binding.mem_state->mem : VK_NULL_HANDLE;
875
876 for (uint32_t region = 0; region < regionCount; region++) {
877 const auto &copy_region = pRegions[region];
878 if (src_mem != VK_NULL_HANDLE) {
879 ResourceAccessRange src_range = MakeMemoryAccessRange(*src_buffer, copy_region.srcOffset, copy_region.size);
880 auto hazard = context->DetectHazard(VulkanTypedHandle(src_mem, kVulkanObjectTypeDeviceMemory),
881 SYNC_TRANSFER_TRANSFER_READ, src_range);
882 if (hazard.hazard) {
883 // TODO -- add tag information to log msg when useful.
locke-lunarga0003652020-03-10 11:38:51 -0600884 skip |= LogError(srcBuffer, string_SyncHazardVUID(hazard.hazard),
885 "vkCmdCopyBuffer: Hazard %s for srcBuffer %s, region %" PRIu32, string_SyncHazard(hazard.hazard),
886 report_data->FormatHandle(srcBuffer).c_str(), region);
John Zulauf9cb530d2019-09-30 14:14:10 -0600887 }
John Zulauf9cb530d2019-09-30 14:14:10 -0600888 }
John Zulauf3d84f1b2020-03-09 13:33:25 -0600889 if ((dst_mem != VK_NULL_HANDLE) && !skip) {
890 ResourceAccessRange dst_range = MakeMemoryAccessRange(*dst_buffer, copy_region.dstOffset, copy_region.size);
891 auto hazard = context->DetectHazard(VulkanTypedHandle(dst_mem, kVulkanObjectTypeDeviceMemory),
892 SYNC_TRANSFER_TRANSFER_WRITE, dst_range);
893 if (hazard.hazard) {
locke-lunarga0003652020-03-10 11:38:51 -0600894 skip |= LogError(dstBuffer, string_SyncHazardVUID(hazard.hazard),
895 "vkCmdCopyBuffer: Hazard %s for dstBuffer %s, region %" PRIu32, string_SyncHazard(hazard.hazard),
896 report_data->FormatHandle(dstBuffer).c_str(), region);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600897 }
898 }
899 if (skip) break;
John Zulauf9cb530d2019-09-30 14:14:10 -0600900 }
901 return skip;
902}
903
904void SyncValidator::PreCallRecordCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
905 uint32_t regionCount, const VkBufferCopy *pRegions) {
John Zulauf3d84f1b2020-03-09 13:33:25 -0600906 auto *cb_context = GetAccessContext(commandBuffer);
907 assert(cb_context);
908 auto *context = cb_context->GetCurrentAccessContext();
909
John Zulauf9cb530d2019-09-30 14:14:10 -0600910 const auto *src_buffer = Get<BUFFER_STATE>(srcBuffer);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600911 const auto src_mem = (src_buffer && !src_buffer->sparse) ? src_buffer->binding.mem_state->mem : VK_NULL_HANDLE;
912 const VulkanTypedHandle src_handle(src_mem, kVulkanObjectTypeDeviceMemory);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600913
John Zulauf9cb530d2019-09-30 14:14:10 -0600914 const auto *dst_buffer = Get<BUFFER_STATE>(dstBuffer);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600915 const auto dst_mem = (dst_buffer && !dst_buffer->sparse) ? dst_buffer->binding.mem_state->mem : VK_NULL_HANDLE;
916 const VulkanTypedHandle dst_handle(dst_mem, kVulkanObjectTypeDeviceMemory);
John Zulauf9cb530d2019-09-30 14:14:10 -0600917
918 for (uint32_t region = 0; region < regionCount; region++) {
919 const auto &copy_region = pRegions[region];
John Zulauf3d84f1b2020-03-09 13:33:25 -0600920 if (src_mem) {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700921 ResourceAccessRange src_range = MakeMemoryAccessRange(*src_buffer, copy_region.srcOffset, copy_region.size);
John Zulauf5f13a792020-03-10 07:31:21 -0600922 context->UpdateAccessState(src_handle, SYNC_TRANSFER_TRANSFER_READ, src_range, tag);
John Zulauf9cb530d2019-09-30 14:14:10 -0600923 }
John Zulauf3d84f1b2020-03-09 13:33:25 -0600924 if (dst_mem) {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700925 ResourceAccessRange dst_range = MakeMemoryAccessRange(*dst_buffer, copy_region.dstOffset, copy_region.size);
John Zulauf5f13a792020-03-10 07:31:21 -0600926 context->UpdateAccessState(dst_handle, SYNC_TRANSFER_TRANSFER_WRITE, dst_range, tag);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700927 }
928 }
929}
930
931bool SyncValidator::PreCallValidateCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
932 VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
933 const VkImageCopy *pRegions) const {
934 bool skip = false;
John Zulauf3d84f1b2020-03-09 13:33:25 -0600935 const auto *cb_access_context = GetAccessContext(commandBuffer);
936 assert(cb_access_context);
937 if (!cb_access_context) return skip;
John Zulauf5c5e88d2019-12-26 11:22:02 -0700938
John Zulauf3d84f1b2020-03-09 13:33:25 -0600939 const auto *context = cb_access_context->GetCurrentAccessContext();
940 assert(context);
941 if (!context) return skip;
942
943 const auto *src_image = Get<IMAGE_STATE>(srcImage);
944 const auto *dst_image = Get<IMAGE_STATE>(dstImage);
945
946 for (uint32_t region = 0; region < regionCount; region++) {
947 const auto &copy_region = pRegions[region];
948 if (src_image) {
949 auto hazard = context->DetectHazard(*src_image, SYNC_TRANSFER_TRANSFER_READ, copy_region.srcSubresource,
950 copy_region.srcOffset, copy_region.extent);
951 if (hazard.hazard) {
locke-lunarga0003652020-03-10 11:38:51 -0600952 skip |= LogError(srcImage, string_SyncHazardVUID(hazard.hazard),
953 "vkCmdCopyImage: Hazard %s for srcImage %s, region %" PRIu32, string_SyncHazard(hazard.hazard),
954 report_data->FormatHandle(srcImage).c_str(), region);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700955 }
John Zulauf3d84f1b2020-03-09 13:33:25 -0600956 }
957
958 if (dst_image) {
locke-lunarg1df1f882020-03-02 16:42:08 -0700959 VkExtent3D dst_copy_extent =
960 GetAdjustedDestImageExtent(src_image->createInfo.format, dst_image->createInfo.format, copy_region.extent);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600961 auto hazard = context->DetectHazard(*dst_image, SYNC_TRANSFER_TRANSFER_WRITE, copy_region.dstSubresource,
locke-lunarg1df1f882020-03-02 16:42:08 -0700962 copy_region.dstOffset, dst_copy_extent);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600963 if (hazard.hazard) {
locke-lunarga0003652020-03-10 11:38:51 -0600964 skip |= LogError(dstImage, string_SyncHazardVUID(hazard.hazard),
965 "vkCmdCopyImage: Hazard %s for dstImage %s, region %" PRIu32, string_SyncHazard(hazard.hazard),
966 report_data->FormatHandle(dstImage).c_str(), region);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700967 }
locke-lunarg1dbbb9e2020-02-28 22:43:53 -0700968 if (skip) break;
John Zulauf5c5e88d2019-12-26 11:22:02 -0700969 }
970 }
John Zulauf3d84f1b2020-03-09 13:33:25 -0600971
John Zulauf5c5e88d2019-12-26 11:22:02 -0700972 return skip;
973}
974
975void SyncValidator::PreCallRecordCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
976 VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
977 const VkImageCopy *pRegions) {
John Zulauf3d84f1b2020-03-09 13:33:25 -0600978 auto *cb_access_context = GetAccessContext(commandBuffer);
979 assert(cb_access_context);
980 auto *context = cb_access_context->GetCurrentAccessContext();
981 assert(context);
982
John Zulauf5c5e88d2019-12-26 11:22:02 -0700983 auto *src_image = Get<IMAGE_STATE>(srcImage);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700984 auto *dst_image = Get<IMAGE_STATE>(dstImage);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700985
986 for (uint32_t region = 0; region < regionCount; region++) {
987 const auto &copy_region = pRegions[region];
John Zulauf3d84f1b2020-03-09 13:33:25 -0600988 if (src_image) {
John Zulauf5f13a792020-03-10 07:31:21 -0600989 context->UpdateAccessState(*src_image, SYNC_TRANSFER_TRANSFER_READ, copy_region.srcSubresource, copy_region.srcOffset,
990 copy_region.extent, tag);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700991 }
John Zulauf3d84f1b2020-03-09 13:33:25 -0600992 if (dst_image) {
locke-lunarg1df1f882020-03-02 16:42:08 -0700993 VkExtent3D dst_copy_extent =
994 GetAdjustedDestImageExtent(src_image->createInfo.format, dst_image->createInfo.format, copy_region.extent);
John Zulauf5f13a792020-03-10 07:31:21 -0600995 context->UpdateAccessState(*dst_image, SYNC_TRANSFER_TRANSFER_WRITE, copy_region.dstSubresource, copy_region.dstOffset,
996 dst_copy_extent, tag);
John Zulauf9cb530d2019-09-30 14:14:10 -0600997 }
998 }
999}
1000
1001bool SyncValidator::PreCallValidateCmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask,
1002 VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags,
1003 uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
1004 uint32_t bufferMemoryBarrierCount,
1005 const VkBufferMemoryBarrier *pBufferMemoryBarriers,
1006 uint32_t imageMemoryBarrierCount,
1007 const VkImageMemoryBarrier *pImageMemoryBarriers) const {
1008 bool skip = false;
John Zulauf3d84f1b2020-03-09 13:33:25 -06001009 const auto *cb_access_context = GetAccessContext(commandBuffer);
1010 assert(cb_access_context);
1011 if (!cb_access_context) return skip;
John Zulauf0cb5be22020-01-23 12:18:22 -07001012
John Zulauf3d84f1b2020-03-09 13:33:25 -06001013 const auto *context = cb_access_context->GetCurrentAccessContext();
1014 assert(context);
1015 if (!context) return skip;
John Zulauf0cb5be22020-01-23 12:18:22 -07001016
John Zulauf3d84f1b2020-03-09 13:33:25 -06001017 const auto src_stage_mask = ExpandPipelineStages(cb_access_context->GetQueueFlags(), srcStageMask);
John Zulauf36bcf6a2020-02-03 15:12:52 -07001018 const auto src_exec_scope = WithEarlierPipelineStages(src_stage_mask);
1019 auto src_stage_accesses = AccessScopeByStage(src_stage_mask);
John Zulauf0cb5be22020-01-23 12:18:22 -07001020 // Validate Image Layout transitions
1021 for (uint32_t index = 0; index < imageMemoryBarrierCount; index++) {
1022 const auto &barrier = pImageMemoryBarriers[index];
1023 if (barrier.newLayout == barrier.oldLayout) continue; // Only interested in layout transitions at this point.
1024 const auto *image_state = Get<IMAGE_STATE>(barrier.image);
1025 if (!image_state) continue;
John Zulauf3d84f1b2020-03-09 13:33:25 -06001026 const auto hazard = DetectImageBarrierHazard(*context, *image_state, src_exec_scope, src_stage_accesses, barrier);
John Zulauf0cb5be22020-01-23 12:18:22 -07001027 if (hazard.hazard) {
1028 // TODO -- add tag information to log msg when useful.
locke-lunarga0003652020-03-10 11:38:51 -06001029 skip |= LogError(barrier.image, string_SyncHazardVUID(hazard.hazard),
1030 "vkCmdPipelineBarrier: Hazard %s for image barrier %" PRIu32 " %s", string_SyncHazard(hazard.hazard),
1031 index, report_data->FormatHandle(barrier.image).c_str());
John Zulauf0cb5be22020-01-23 12:18:22 -07001032 }
1033 }
John Zulauf9cb530d2019-09-30 14:14:10 -06001034
1035 return skip;
1036}
1037
1038void SyncValidator::PreCallRecordCmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask,
1039 VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags,
1040 uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
1041 uint32_t bufferMemoryBarrierCount,
1042 const VkBufferMemoryBarrier *pBufferMemoryBarriers,
1043 uint32_t imageMemoryBarrierCount,
1044 const VkImageMemoryBarrier *pImageMemoryBarriers) {
John Zulauf3d84f1b2020-03-09 13:33:25 -06001045 auto *cb_access_context = GetAccessContext(commandBuffer);
1046 assert(cb_access_context);
1047 if (!cb_access_context) return;
1048 auto access_context = cb_access_context->GetCurrentAccessContext();
1049 assert(access_context);
1050 if (!access_context) return;
John Zulauf9cb530d2019-09-30 14:14:10 -06001051
John Zulauf3d84f1b2020-03-09 13:33:25 -06001052 const auto src_stage_mask = ExpandPipelineStages(cb_access_context->GetQueueFlags(), srcStageMask);
John Zulauf36bcf6a2020-02-03 15:12:52 -07001053 auto src_stage_accesses = AccessScopeByStage(src_stage_mask);
John Zulauf3d84f1b2020-03-09 13:33:25 -06001054 const auto dst_stage_mask = ExpandPipelineStages(cb_access_context->GetQueueFlags(), dstStageMask);
John Zulauf36bcf6a2020-02-03 15:12:52 -07001055 auto dst_stage_accesses = AccessScopeByStage(dst_stage_mask);
1056 const auto src_exec_scope = WithEarlierPipelineStages(src_stage_mask);
1057 const auto dst_exec_scope = WithLaterPipelineStages(dst_stage_mask);
John Zulauf3d84f1b2020-03-09 13:33:25 -06001058 ApplyBufferBarriers(access_context, src_exec_scope, src_stage_accesses, dst_exec_scope, dst_stage_accesses,
1059 bufferMemoryBarrierCount, pBufferMemoryBarriers);
1060 ApplyImageBarriers(access_context, src_exec_scope, src_stage_accesses, dst_exec_scope, dst_stage_accesses,
1061 imageMemoryBarrierCount, pImageMemoryBarriers);
John Zulauf9cb530d2019-09-30 14:14:10 -06001062
1063 // 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 -06001064 ApplyGlobalBarriers(access_context, src_exec_scope, dst_exec_scope, src_stage_accesses, dst_stage_accesses, memoryBarrierCount,
John Zulauf0cb5be22020-01-23 12:18:22 -07001065 pMemoryBarriers);
John Zulauf9cb530d2019-09-30 14:14:10 -06001066}
1067
1068void SyncValidator::PostCallRecordCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo,
1069 const VkAllocationCallbacks *pAllocator, VkDevice *pDevice, VkResult result) {
1070 // The state tracker sets up the device state
1071 StateTracker::PostCallRecordCreateDevice(gpu, pCreateInfo, pAllocator, pDevice, result);
1072
John Zulauf5f13a792020-03-10 07:31:21 -06001073 // Add the callback hooks for the functions that are either broadly or deeply used and that the ValidationStateTracker
1074 // refactor would be messier without.
John Zulauf9cb530d2019-09-30 14:14:10 -06001075 // TODO: Find a good way to do this hooklessly.
1076 ValidationObject *device_object = GetLayerDataPtr(get_dispatch_key(*pDevice), layer_data_map);
1077 ValidationObject *validation_data = GetValidationObject(device_object->object_dispatch, LayerObjectTypeSyncValidation);
1078 SyncValidator *sync_device_state = static_cast<SyncValidator *>(validation_data);
1079
1080 sync_device_state->SetCommandBufferResetCallback(
1081 [sync_device_state](VkCommandBuffer command_buffer) -> void { sync_device_state->ResetCommandBuffer(command_buffer); });
1082}
John Zulauf3d84f1b2020-03-09 13:33:25 -06001083
1084void SyncValidator::PostCallRecordBeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo,
1085 VkResult result) {
1086 // The state tracker sets up the command buffer state
1087 StateTracker::PostCallRecordBeginCommandBuffer(commandBuffer, pBeginInfo, result);
1088
1089 // Create/initialize the structure that trackers accesses at the command buffer scope.
1090 auto cb_access_context = GetAccessContext(commandBuffer);
1091 assert(cb_access_context);
1092 cb_access_context->Reset();
1093}
1094
1095void SyncValidator::RecordCmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
1096 const VkSubpassBeginInfo *pSubpassBeginInfo) {
1097 const auto rp_state = Get<RENDER_PASS_STATE>(pRenderPassBegin->renderPass);
1098 auto cb_context = GetAccessContext(commandBuffer);
1099 if (rp_state && cb_context) {
1100 cb_context->BeginRenderPass(*rp_state);
1101 }
1102}
1103
1104void SyncValidator::PostCallRecordCmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
1105 VkSubpassContents contents) {
1106 StateTracker::PostCallRecordCmdBeginRenderPass(commandBuffer, pRenderPassBegin, contents);
1107 auto subpass_begin_info = lvl_init_struct<VkSubpassBeginInfo>();
1108 subpass_begin_info.contents = contents;
1109 RecordCmdBeginRenderPass(commandBuffer, pRenderPassBegin, &subpass_begin_info);
1110}
1111
1112void SyncValidator::PostCallRecordCmdBeginRenderPass2(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
1113 const VkSubpassBeginInfo *pSubpassBeginInfo) {
1114 StateTracker::PostCallRecordCmdBeginRenderPass2(commandBuffer, pRenderPassBegin, pSubpassBeginInfo);
1115 RecordCmdBeginRenderPass(commandBuffer, pRenderPassBegin, pSubpassBeginInfo);
1116}
1117
1118void SyncValidator::PostCallRecordCmdBeginRenderPass2KHR(VkCommandBuffer commandBuffer,
1119 const VkRenderPassBeginInfo *pRenderPassBegin,
1120 const VkSubpassBeginInfo *pSubpassBeginInfo) {
1121 StateTracker::PostCallRecordCmdBeginRenderPass2KHR(commandBuffer, pRenderPassBegin, pSubpassBeginInfo);
1122 RecordCmdBeginRenderPass(commandBuffer, pRenderPassBegin, pSubpassBeginInfo);
1123}
1124
1125void SyncValidator::RecordCmdNextSubpass(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo *pSubpassBeginInfo,
1126 const VkSubpassEndInfo *pSubpassEndInfo) {
1127 auto cb_context = GetAccessContext(commandBuffer);
1128 assert(cb_context);
1129 auto cb_state = cb_context->GetCommandBufferState();
1130 if (!cb_state) return;
1131
1132 auto rp_state = cb_state->activeRenderPass;
1133 if (!rp_state) return;
1134
1135 cb_context->NextRenderPass(*rp_state);
1136}
1137
1138void SyncValidator::PostCallRecordCmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents) {
1139 StateTracker::PostCallRecordCmdNextSubpass(commandBuffer, contents);
1140 auto subpass_begin_info = lvl_init_struct<VkSubpassBeginInfo>();
1141 subpass_begin_info.contents = contents;
1142 RecordCmdNextSubpass(commandBuffer, &subpass_begin_info, nullptr);
1143}
1144
1145void SyncValidator::PostCallRecordCmdNextSubpass2(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo *pSubpassBeginInfo,
1146 const VkSubpassEndInfo *pSubpassEndInfo) {
1147 StateTracker::PostCallRecordCmdNextSubpass2(commandBuffer, pSubpassBeginInfo, pSubpassEndInfo);
1148 RecordCmdNextSubpass(commandBuffer, pSubpassBeginInfo, pSubpassEndInfo);
1149}
1150
1151void SyncValidator::PostCallRecordCmdNextSubpass2KHR(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo *pSubpassBeginInfo,
1152 const VkSubpassEndInfo *pSubpassEndInfo) {
1153 StateTracker::PostCallRecordCmdNextSubpass2KHR(commandBuffer, pSubpassBeginInfo, pSubpassEndInfo);
1154 RecordCmdNextSubpass(commandBuffer, pSubpassBeginInfo, pSubpassEndInfo);
1155}
1156
1157void SyncValidator::RecordCmdEndRenderPass(VkCommandBuffer commandBuffer, const VkSubpassEndInfo *pSubpassEndInfo) {}
1158
1159void SyncValidator::PostCallRecordCmdEndRenderPass(VkCommandBuffer commandBuffer) {
1160 StateTracker::PostCallRecordCmdEndRenderPass(commandBuffer);
1161 RecordCmdEndRenderPass(commandBuffer, nullptr);
1162}
1163
1164void SyncValidator::PostCallRecordCmdEndRenderPass2(VkCommandBuffer commandBuffer, const VkSubpassEndInfo *pSubpassEndInfo) {
1165 StateTracker::PostCallRecordCmdEndRenderPass2(commandBuffer, pSubpassEndInfo);
1166 RecordCmdEndRenderPass(commandBuffer, pSubpassEndInfo);
1167}
1168
1169void SyncValidator::PostCallRecordCmdEndRenderPass2KHR(VkCommandBuffer commandBuffer, const VkSubpassEndInfo *pSubpassEndInfo) {
1170 StateTracker::PostCallRecordCmdEndRenderPass2KHR(commandBuffer, pSubpassEndInfo);
1171 RecordCmdEndRenderPass(commandBuffer, pSubpassEndInfo);
1172}
locke-lunarga19c71d2020-03-02 18:17:04 -07001173
1174bool SyncValidator::PreCallValidateCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage,
1175 VkImageLayout dstImageLayout, uint32_t regionCount,
1176 const VkBufferImageCopy *pRegions) const {
1177 bool skip = false;
1178 const auto *cb_access_context = GetAccessContext(commandBuffer);
1179 assert(cb_access_context);
1180 if (!cb_access_context) return skip;
1181
1182 const auto *context = cb_access_context->GetCurrentAccessContext();
1183 assert(context);
1184 if (!context) return skip;
1185
1186 const auto *src_buffer = Get<BUFFER_STATE>(srcBuffer);
1187 const auto src_mem = (src_buffer && !src_buffer->sparse) ? src_buffer->binding.mem_state->mem : VK_NULL_HANDLE;
1188 const auto *dst_image = Get<IMAGE_STATE>(dstImage);
1189
1190 for (uint32_t region = 0; region < regionCount; region++) {
1191 const auto &copy_region = pRegions[region];
1192 if (src_mem) {
1193 ResourceAccessRange src_range = MakeMemoryAccessRange(
1194 *src_buffer, copy_region.bufferOffset, GetBufferSizeFromCopyImage(copy_region, dst_image->createInfo.format));
1195 auto hazard = context->DetectHazard(VulkanTypedHandle(src_mem, kVulkanObjectTypeDeviceMemory),
1196 SYNC_TRANSFER_TRANSFER_READ, src_range);
1197 if (hazard.hazard) {
1198 // TODO -- add tag information to log msg when useful.
locke-lunarga0003652020-03-10 11:38:51 -06001199 skip |= LogError(srcBuffer, string_SyncHazardVUID(hazard.hazard),
1200 "vkCmdCopyBufferToImage: Hazard %s for srcBuffer %s, region %" PRIu32,
locke-lunarga19c71d2020-03-02 18:17:04 -07001201 string_SyncHazard(hazard.hazard), report_data->FormatHandle(srcBuffer).c_str(), region);
1202 }
1203 }
1204 if (dst_image) {
1205 auto hazard = context->DetectHazard(*dst_image, SYNC_TRANSFER_TRANSFER_WRITE, copy_region.imageSubresource,
1206 copy_region.imageOffset, copy_region.imageExtent);
1207 if (hazard.hazard) {
locke-lunarga0003652020-03-10 11:38:51 -06001208 skip |= LogError(dstImage, string_SyncHazardVUID(hazard.hazard),
1209 "vkCmdCopyBufferToImage: Hazard %s for dstImage %s, region %" PRIu32,
locke-lunarga19c71d2020-03-02 18:17:04 -07001210 string_SyncHazard(hazard.hazard), report_data->FormatHandle(dstImage).c_str(), region);
1211 }
1212 if (skip) break;
1213 }
1214 if (skip) break;
1215 }
1216 return skip;
1217}
1218
1219void SyncValidator::PreCallRecordCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage,
1220 VkImageLayout dstImageLayout, uint32_t regionCount,
1221 const VkBufferImageCopy *pRegions) {
1222 auto *cb_access_context = GetAccessContext(commandBuffer);
1223 assert(cb_access_context);
1224 auto *context = cb_access_context->GetCurrentAccessContext();
1225 assert(context);
1226
1227 const auto *src_buffer = Get<BUFFER_STATE>(srcBuffer);
1228 const auto src_mem = (src_buffer && !src_buffer->sparse) ? src_buffer->binding.mem_state->mem : VK_NULL_HANDLE;
1229 const VulkanTypedHandle src_handle(src_mem, kVulkanObjectTypeDeviceMemory);
John Zulauf5f13a792020-03-10 07:31:21 -06001230
locke-lunarga19c71d2020-03-02 18:17:04 -07001231 auto *dst_image = Get<IMAGE_STATE>(dstImage);
locke-lunarga19c71d2020-03-02 18:17:04 -07001232
1233 for (uint32_t region = 0; region < regionCount; region++) {
1234 const auto &copy_region = pRegions[region];
1235 if (src_buffer) {
1236 ResourceAccessRange src_range = MakeMemoryAccessRange(
1237 *src_buffer, copy_region.bufferOffset, GetBufferSizeFromCopyImage(copy_region, dst_image->createInfo.format));
John Zulauf5f13a792020-03-10 07:31:21 -06001238 context->UpdateAccessState(src_handle, SYNC_TRANSFER_TRANSFER_READ, src_range, tag);
locke-lunarga19c71d2020-03-02 18:17:04 -07001239 }
1240 if (dst_image) {
John Zulauf5f13a792020-03-10 07:31:21 -06001241 context->UpdateAccessState(*dst_image, SYNC_TRANSFER_TRANSFER_WRITE, copy_region.imageSubresource,
1242 copy_region.imageOffset, copy_region.imageExtent, tag);
locke-lunarga19c71d2020-03-02 18:17:04 -07001243 }
1244 }
1245}
1246
1247bool SyncValidator::PreCallValidateCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage,
1248 VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount,
1249 const VkBufferImageCopy *pRegions) const {
1250 bool skip = false;
1251 const auto *cb_access_context = GetAccessContext(commandBuffer);
1252 assert(cb_access_context);
1253 if (!cb_access_context) return skip;
1254
1255 const auto *context = cb_access_context->GetCurrentAccessContext();
1256 assert(context);
1257 if (!context) return skip;
1258
1259 const auto *src_image = Get<IMAGE_STATE>(srcImage);
1260 const auto *dst_buffer = Get<BUFFER_STATE>(dstBuffer);
1261 const auto dst_mem = (dst_buffer && !dst_buffer->sparse) ? dst_buffer->binding.mem_state->mem : VK_NULL_HANDLE;
1262 for (uint32_t region = 0; region < regionCount; region++) {
1263 const auto &copy_region = pRegions[region];
1264 if (src_image) {
1265 auto hazard = context->DetectHazard(*src_image, SYNC_TRANSFER_TRANSFER_READ, copy_region.imageSubresource,
1266 copy_region.imageOffset, copy_region.imageExtent);
1267 if (hazard.hazard) {
locke-lunarga0003652020-03-10 11:38:51 -06001268 skip |= LogError(srcImage, string_SyncHazardVUID(hazard.hazard),
1269 "vkCmdCopyImageToBuffer: Hazard %s for srcImage %s, region %" PRIu32,
locke-lunarga19c71d2020-03-02 18:17:04 -07001270 string_SyncHazard(hazard.hazard), report_data->FormatHandle(srcImage).c_str(), region);
1271 }
1272 }
1273 if (dst_mem) {
1274 ResourceAccessRange dst_range = MakeMemoryAccessRange(
1275 *dst_buffer, copy_region.bufferOffset, GetBufferSizeFromCopyImage(copy_region, src_image->createInfo.format));
1276 auto hazard = context->DetectHazard(VulkanTypedHandle(dst_mem, kVulkanObjectTypeDeviceMemory),
1277 SYNC_TRANSFER_TRANSFER_WRITE, dst_range);
1278 if (hazard.hazard) {
locke-lunarga0003652020-03-10 11:38:51 -06001279 skip |= LogError(dstBuffer, string_SyncHazardVUID(hazard.hazard),
1280 "vkCmdCopyImageToBuffer: Hazard %s for dstBuffer %s, region %" PRIu32,
locke-lunarga19c71d2020-03-02 18:17:04 -07001281 string_SyncHazard(hazard.hazard), report_data->FormatHandle(dstBuffer).c_str(), region);
1282 }
1283 }
1284 if (skip) break;
1285 }
1286 return skip;
1287}
1288
1289void SyncValidator::PreCallRecordCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
1290 VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy *pRegions) {
1291 auto *cb_access_context = GetAccessContext(commandBuffer);
1292 assert(cb_access_context);
1293 auto *context = cb_access_context->GetCurrentAccessContext();
1294 assert(context);
1295
1296 const auto *src_image = Get<IMAGE_STATE>(srcImage);
locke-lunarga19c71d2020-03-02 18:17:04 -07001297 auto *dst_buffer = Get<BUFFER_STATE>(dstBuffer);
1298 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 -06001299 const VulkanTypedHandle dst_handle(dst_mem, kVulkanObjectTypeDeviceMemory);
locke-lunarga19c71d2020-03-02 18:17:04 -07001300
1301 for (uint32_t region = 0; region < regionCount; region++) {
1302 const auto &copy_region = pRegions[region];
1303 if (src_image) {
John Zulauf5f13a792020-03-10 07:31:21 -06001304 context->UpdateAccessState(*src_image, SYNC_TRANSFER_TRANSFER_READ, copy_region.imageSubresource,
1305 copy_region.imageOffset, copy_region.imageExtent, tag);
locke-lunarga19c71d2020-03-02 18:17:04 -07001306 }
1307 if (dst_buffer) {
1308 ResourceAccessRange dst_range = MakeMemoryAccessRange(
1309 *dst_buffer, copy_region.bufferOffset, GetBufferSizeFromCopyImage(copy_region, src_image->createInfo.format));
John Zulauf5f13a792020-03-10 07:31:21 -06001310 context->UpdateAccessState(dst_handle, SYNC_TRANSFER_TRANSFER_WRITE, dst_range, tag);
locke-lunarga19c71d2020-03-02 18:17:04 -07001311 }
1312 }
1313}
1314
1315bool SyncValidator::PreCallValidateCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
1316 VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
1317 const VkImageBlit *pRegions, VkFilter filter) const {
1318 bool skip = false;
1319 const auto *cb_access_context = GetAccessContext(commandBuffer);
1320 assert(cb_access_context);
1321 if (!cb_access_context) return skip;
1322
1323 const auto *context = cb_access_context->GetCurrentAccessContext();
1324 assert(context);
1325 if (!context) return skip;
1326
1327 const auto *src_image = Get<IMAGE_STATE>(srcImage);
1328 const auto *dst_image = Get<IMAGE_STATE>(dstImage);
1329
1330 for (uint32_t region = 0; region < regionCount; region++) {
1331 const auto &blit_region = pRegions[region];
1332 if (src_image) {
1333 VkExtent3D extent = {static_cast<uint32_t>(blit_region.srcOffsets[1].x - blit_region.srcOffsets[0].x),
1334 static_cast<uint32_t>(blit_region.srcOffsets[1].y - blit_region.srcOffsets[0].y),
1335 static_cast<uint32_t>(blit_region.srcOffsets[1].z - blit_region.srcOffsets[0].z)};
1336 auto hazard = context->DetectHazard(*src_image, SYNC_TRANSFER_TRANSFER_READ, blit_region.srcSubresource,
1337 blit_region.srcOffsets[0], extent);
1338 if (hazard.hazard) {
locke-lunarga0003652020-03-10 11:38:51 -06001339 skip |= LogError(srcImage, string_SyncHazardVUID(hazard.hazard),
1340 "vkCmdBlitImage: Hazard %s for srcImage %s, region %" PRIu32, string_SyncHazard(hazard.hazard),
1341 report_data->FormatHandle(srcImage).c_str(), region);
locke-lunarga19c71d2020-03-02 18:17:04 -07001342 }
1343 }
1344
1345 if (dst_image) {
1346 VkExtent3D extent = {static_cast<uint32_t>(blit_region.dstOffsets[1].x - blit_region.dstOffsets[0].x),
1347 static_cast<uint32_t>(blit_region.dstOffsets[1].y - blit_region.dstOffsets[0].y),
1348 static_cast<uint32_t>(blit_region.dstOffsets[1].z - blit_region.dstOffsets[0].z)};
1349 auto hazard = context->DetectHazard(*dst_image, SYNC_TRANSFER_TRANSFER_WRITE, blit_region.dstSubresource,
1350 blit_region.dstOffsets[0], extent);
1351 if (hazard.hazard) {
locke-lunarga0003652020-03-10 11:38:51 -06001352 skip |= LogError(dstImage, string_SyncHazardVUID(hazard.hazard),
1353 "vkCmdBlitImage: Hazard %s for dstImage %s, region %" PRIu32, string_SyncHazard(hazard.hazard),
1354 report_data->FormatHandle(dstImage).c_str(), region);
locke-lunarga19c71d2020-03-02 18:17:04 -07001355 }
1356 if (skip) break;
1357 }
1358 }
1359
1360 return skip;
1361}
1362
1363void SyncValidator::PreCallRecordCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
1364 VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
1365 const VkImageBlit *pRegions, VkFilter filter) {
1366 auto *cb_access_context = GetAccessContext(commandBuffer);
1367 assert(cb_access_context);
1368 auto *context = cb_access_context->GetCurrentAccessContext();
1369 assert(context);
1370
1371 auto *src_image = Get<IMAGE_STATE>(srcImage);
locke-lunarga19c71d2020-03-02 18:17:04 -07001372 auto *dst_image = Get<IMAGE_STATE>(dstImage);
locke-lunarga19c71d2020-03-02 18:17:04 -07001373
1374 for (uint32_t region = 0; region < regionCount; region++) {
1375 const auto &blit_region = pRegions[region];
1376 if (src_image) {
1377 VkExtent3D extent = {static_cast<uint32_t>(blit_region.srcOffsets[1].x - blit_region.srcOffsets[0].x),
1378 static_cast<uint32_t>(blit_region.srcOffsets[1].y - blit_region.srcOffsets[0].y),
1379 static_cast<uint32_t>(blit_region.srcOffsets[1].z - blit_region.srcOffsets[0].z)};
John Zulauf5f13a792020-03-10 07:31:21 -06001380 context->UpdateAccessState(*src_image, SYNC_TRANSFER_TRANSFER_READ, blit_region.srcSubresource,
1381 blit_region.srcOffsets[0], extent, tag);
locke-lunarga19c71d2020-03-02 18:17:04 -07001382 }
1383 if (dst_image) {
1384 VkExtent3D extent = {static_cast<uint32_t>(blit_region.dstOffsets[1].x - blit_region.dstOffsets[0].x),
1385 static_cast<uint32_t>(blit_region.dstOffsets[1].y - blit_region.dstOffsets[0].y),
1386 static_cast<uint32_t>(blit_region.dstOffsets[1].z - blit_region.dstOffsets[0].z)};
John Zulauf5f13a792020-03-10 07:31:21 -06001387 context->UpdateAccessState(*dst_image, SYNC_TRANSFER_TRANSFER_WRITE, blit_region.dstSubresource,
1388 blit_region.dstOffsets[0], extent, tag);
locke-lunarga19c71d2020-03-02 18:17:04 -07001389 }
1390 }
1391}