blob: ac97852aac409d47ea09b1766b3b0612465a9b86 [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:
27 return "SYNC-NONE";
28 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;
38 default:
39 assert(0);
40 }
41 return "SYNC-HAZARD-INVALID";
42}
43
44static const char *string_SyncHazard(SyncHazard hazard) {
45 switch (hazard) {
46 case SyncHazard::NONE:
47 return "NONR";
48 break;
49 case SyncHazard::READ_AFTER_WRITE:
50 return "READ_AFTER_WRITE";
51 break;
52 case SyncHazard::WRITE_AFTER_READ:
53 return "WRITE_AFTER_READ";
54 break;
55 case SyncHazard::WRITE_AFTER_WRITE:
56 return "WRITE_AFTER_WRITE";
57 break;
58 default:
59 assert(0);
60 }
61 return "INVALID HAZARD";
62}
63
John Zulauf0cb5be22020-01-23 12:18:22 -070064// Expand the pipeline stage without regard to whether the are valid w.r.t. queue or extension
65VkPipelineStageFlags ExpandPipelineStages(VkQueueFlags queue_flags, VkPipelineStageFlags stage_mask) {
66 VkPipelineStageFlags expanded = stage_mask;
67 if (VK_PIPELINE_STAGE_ALL_COMMANDS_BIT & stage_mask) {
68 expanded = expanded & ~VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
69 for (const auto &all_commands : syncAllCommandStagesByQueueFlags) {
70 if (all_commands.first & queue_flags) {
71 expanded |= all_commands.second;
72 }
73 }
74 }
75 if (VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT & stage_mask) {
76 expanded = expanded & ~VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
77 expanded |= syncAllCommandStagesByQueueFlags.at(VK_QUEUE_GRAPHICS_BIT) & ~VK_PIPELINE_STAGE_HOST_BIT;
78 }
79 return expanded;
80}
81
John Zulauf36bcf6a2020-02-03 15:12:52 -070082VkPipelineStageFlags RelatedPipelineStages(VkPipelineStageFlags stage_mask,
83 std::map<VkPipelineStageFlagBits, VkPipelineStageFlags> &map) {
84 VkPipelineStageFlags unscanned = stage_mask;
85 VkPipelineStageFlags related = 0;
86 for (const auto entry : map) {
87 const auto stage = entry.first;
88 if (stage & unscanned) {
89 related = related | entry.second;
90 unscanned = unscanned & ~stage;
91 if (!unscanned) break;
92 }
93 }
94 return related;
95}
96
97VkPipelineStageFlags WithEarlierPipelineStages(VkPipelineStageFlags stage_mask) {
98 return stage_mask | RelatedPipelineStages(stage_mask, syncLogicallyEarlierStages);
99}
100
101VkPipelineStageFlags WithLaterPipelineStages(VkPipelineStageFlags stage_mask) {
102 return stage_mask | RelatedPipelineStages(stage_mask, syncLogicallyLaterStages);
103}
104
John Zulauf5c5e88d2019-12-26 11:22:02 -0700105static const ResourceAccessRange full_range(std::numeric_limits<VkDeviceSize>::min(), std::numeric_limits<VkDeviceSize>::max());
106static ResourceAccessRange MakeMemoryAccessRange(const BUFFER_STATE &buffer, VkDeviceSize offset, VkDeviceSize size) {
John Zulauf9cb530d2019-09-30 14:14:10 -0600107 assert(!buffer.sparse);
108 const auto base = offset + buffer.binding.offset;
John Zulauf5c5e88d2019-12-26 11:22:02 -0700109 return ResourceAccessRange(base, base + size);
110}
111
112HazardResult DetectHazard(const ResourceAccessRangeMap &accesses, SyncStageAccessIndex current_usage,
113 const ResourceAccessRange &range) {
114 const auto from = accesses.lower_bound(range);
115 const auto to = accesses.upper_bound(range);
116 for (auto pos = from; pos != to; ++pos) {
117 const auto &access_state = pos->second;
118 HazardResult hazard = access_state.DetectHazard(current_usage);
119 if (hazard.hazard) return hazard;
120 }
121 return HazardResult();
122}
123
124HazardResult DetectHazard(const IMAGE_STATE &image, const ResourceAccessRangeMap &accesses, SyncStageAccessIndex current_usage,
125 const VkImageSubresourceLayers &subresource, const VkOffset3D &offset, const VkExtent3D &extent) {
126 // TODO: replace the encoder/generator with offset3D/extent3D aware versions
127 VkImageSubresourceRange subresource_range = {subresource.aspectMask, subresource.mipLevel, 1, subresource.baseArrayLayer,
128 subresource.layerCount};
129 subresource_adapter::RangeGenerator range_gen(image.range_encoder, subresource_range);
130 for (; range_gen->non_empty(); ++range_gen) {
131 HazardResult hazard = DetectHazard(accesses, current_usage, *range_gen);
132 if (hazard.hazard) return hazard;
133 }
134 return HazardResult();
John Zulauf9cb530d2019-09-30 14:14:10 -0600135}
136
John Zulauf0cb5be22020-01-23 12:18:22 -0700137HazardResult DetectBarrierHazard(const ResourceAccessRangeMap &accesses, SyncStageAccessIndex current_usage,
John Zulauf36bcf6a2020-02-03 15:12:52 -0700138 VkPipelineStageFlags src_exec_scope, SyncStageAccessFlags src_access_scope,
John Zulauf0cb5be22020-01-23 12:18:22 -0700139 const ResourceAccessRange &range) {
140 const auto from = accesses.lower_bound(range);
141 const auto to = accesses.upper_bound(range);
142 for (auto pos = from; pos != to; ++pos) {
143 const auto &access_state = pos->second;
John Zulauf36bcf6a2020-02-03 15:12:52 -0700144 HazardResult hazard = access_state.DetectBarrierHazard(current_usage, src_exec_scope, src_access_scope);
John Zulauf0cb5be22020-01-23 12:18:22 -0700145 if (hazard.hazard) return hazard;
146 }
147 return HazardResult();
148}
149
150HazardResult DetectImageBarrierHazard(const ResourceAccessTracker &tracker, const IMAGE_STATE &image,
John Zulauf36bcf6a2020-02-03 15:12:52 -0700151 VkPipelineStageFlags src_exec_scope, SyncStageAccessFlags src_stage_accesses,
John Zulauf0cb5be22020-01-23 12:18:22 -0700152 const VkImageMemoryBarrier &barrier) {
153 auto *accesses = tracker.GetImageAccesses(image.image);
154 if (!accesses) return HazardResult();
155
156 auto subresource_range = NormalizeSubresourceRange(image.createInfo, barrier.subresourceRange);
157 subresource_adapter::RangeGenerator range_gen(image.range_encoder, subresource_range);
John Zulauf36bcf6a2020-02-03 15:12:52 -0700158 const auto src_access_scope = SyncStageAccess::AccessScope(src_stage_accesses, barrier.srcAccessMask);
John Zulauf0cb5be22020-01-23 12:18:22 -0700159 for (; range_gen->non_empty(); ++range_gen) {
John Zulauf36bcf6a2020-02-03 15:12:52 -0700160 HazardResult hazard = DetectBarrierHazard(*accesses, SyncStageAccessIndex::SYNC_IMAGE_LAYOUT_TRANSITION, src_exec_scope,
161 src_access_scope, *range_gen);
John Zulauf0cb5be22020-01-23 12:18:22 -0700162 if (hazard.hazard) return hazard;
163 }
164 return HazardResult();
165}
166
John Zulauf9cb530d2019-09-30 14:14:10 -0600167template <typename Flags, typename Map>
168SyncStageAccessFlags AccessScopeImpl(Flags flag_mask, const Map &map) {
169 SyncStageAccessFlags scope = 0;
170 for (const auto &bit_scope : map) {
171 if (flag_mask < bit_scope.first) break;
172
173 if (flag_mask & bit_scope.first) {
174 scope |= bit_scope.second;
175 }
176 }
177 return scope;
178}
179
180SyncStageAccessFlags SyncStageAccess::AccessScopeByStage(VkPipelineStageFlags stages) {
181 return AccessScopeImpl(stages, syncStageAccessMaskByStageBit);
182}
183
184SyncStageAccessFlags SyncStageAccess::AccessScopeByAccess(VkAccessFlags accesses) {
185 return AccessScopeImpl(accesses, syncStageAccessMaskByAccessBit);
186}
187
188// Getting from stage mask and access mask to stage/acess masks is something we need to be good at...
189SyncStageAccessFlags SyncStageAccess::AccessScope(VkPipelineStageFlags stages, VkAccessFlags accesses) {
190 // The access scope is the intersection of all stage/access types possible for the enabled stages and the enables accesses
191 // (after doing a couple factoring of common terms the union of stage/access intersections is the intersections of the
192 // union of all stage/access types for all the stages and the same unions for the access mask...
193 return AccessScopeByStage(stages) & AccessScopeByAccess(accesses);
194}
195
196template <typename Action>
John Zulauf5c5e88d2019-12-26 11:22:02 -0700197void UpdateMemoryAccessState(ResourceAccessRangeMap *accesses, const ResourceAccessRange &range, const Action &action) {
John Zulauf9cb530d2019-09-30 14:14:10 -0600198 // TODO -- region/mem-range accuracte update
199 auto pos = accesses->lower_bound(range);
200 if (pos == accesses->end() || !pos->first.intersects(range)) {
201 // The range is empty, fill it with a default value.
202 pos = action.Infill(accesses, pos, range);
203 } else if (range.begin < pos->first.begin) {
204 // Leading empty space, infill
John Zulauf5c5e88d2019-12-26 11:22:02 -0700205 pos = action.Infill(accesses, pos, ResourceAccessRange(range.begin, pos->first.begin));
John Zulauf9cb530d2019-09-30 14:14:10 -0600206 } else if (pos->first.begin < range.begin) {
207 // Trim the beginning if needed
208 pos = accesses->split(pos, range.begin, sparse_container::split_op_keep_both());
209 ++pos;
210 }
211
212 const auto the_end = accesses->end();
213 while ((pos != the_end) && pos->first.intersects(range)) {
214 if (pos->first.end > range.end) {
215 pos = accesses->split(pos, range.end, sparse_container::split_op_keep_both());
216 }
217
218 pos = action(accesses, pos);
219 if (pos == the_end) break;
220
221 auto next = pos;
222 ++next;
223 if ((pos->first.end < range.end) && (next != the_end) && !next->first.is_subsequent_to(pos->first)) {
224 // Need to infill if next is disjoint
225 VkDeviceSize limit = (next == the_end) ? range.end : std::min(range.end, next->first.begin);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700226 ResourceAccessRange new_range(pos->first.end, limit);
John Zulauf9cb530d2019-09-30 14:14:10 -0600227 next = action.Infill(accesses, next, new_range);
228 }
229 pos = next;
230 }
231}
232
233struct UpdateMemoryAccessStateFunctor {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700234 using Iterator = ResourceAccessRangeMap::iterator;
235 Iterator Infill(ResourceAccessRangeMap *accesses, Iterator pos, ResourceAccessRange range) const {
John Zulauf9cb530d2019-09-30 14:14:10 -0600236 return accesses->insert(pos, std::make_pair(range, ResourceAccessState()));
237 }
John Zulauf5c5e88d2019-12-26 11:22:02 -0700238 Iterator operator()(ResourceAccessRangeMap *accesses, Iterator pos) const {
John Zulauf9cb530d2019-09-30 14:14:10 -0600239 auto &access_state = pos->second;
240 access_state.Update(usage, tag);
241 return pos;
242 }
243
244 UpdateMemoryAccessStateFunctor(SyncStageAccessIndex usage_, const ResourceUsageTag &tag_) : usage(usage_), tag(tag_) {}
245 SyncStageAccessIndex usage;
246 const ResourceUsageTag &tag;
247};
248
249struct ApplyMemoryAccessBarrierFunctor {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700250 using Iterator = ResourceAccessRangeMap::iterator;
251 inline Iterator Infill(ResourceAccessRangeMap *accesses, Iterator pos, ResourceAccessRange range) const { return pos; }
John Zulauf9cb530d2019-09-30 14:14:10 -0600252
John Zulauf5c5e88d2019-12-26 11:22:02 -0700253 Iterator operator()(ResourceAccessRangeMap *accesses, Iterator pos) const {
John Zulauf9cb530d2019-09-30 14:14:10 -0600254 auto &access_state = pos->second;
John Zulauf36bcf6a2020-02-03 15:12:52 -0700255 access_state.ApplyMemoryAccessBarrier(src_exec_scope, src_access_scope, dst_exec_scope, dst_access_scope);
John Zulauf9cb530d2019-09-30 14:14:10 -0600256 return pos;
257 }
258
John Zulauf36bcf6a2020-02-03 15:12:52 -0700259 ApplyMemoryAccessBarrierFunctor(VkPipelineStageFlags src_exec_scope_, SyncStageAccessFlags src_access_scope_,
260 VkPipelineStageFlags dst_exec_scope_, SyncStageAccessFlags dst_access_scope_)
261 : src_exec_scope(src_exec_scope_),
262 src_access_scope(src_access_scope_),
263 dst_exec_scope(dst_exec_scope_),
264 dst_access_scope(dst_access_scope_) {}
John Zulauf9cb530d2019-09-30 14:14:10 -0600265
John Zulauf36bcf6a2020-02-03 15:12:52 -0700266 VkPipelineStageFlags src_exec_scope;
267 SyncStageAccessFlags src_access_scope;
268 VkPipelineStageFlags dst_exec_scope;
269 SyncStageAccessFlags dst_access_scope;
John Zulauf9cb530d2019-09-30 14:14:10 -0600270};
271
272struct ApplyGlobalBarrierFunctor {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700273 using Iterator = ResourceAccessRangeMap::iterator;
274 inline Iterator Infill(ResourceAccessRangeMap *accesses, Iterator pos, ResourceAccessRange range) const { return pos; }
John Zulauf9cb530d2019-09-30 14:14:10 -0600275
John Zulauf5c5e88d2019-12-26 11:22:02 -0700276 Iterator operator()(ResourceAccessRangeMap *accesses, Iterator pos) const {
John Zulauf9cb530d2019-09-30 14:14:10 -0600277 auto &access_state = pos->second;
John Zulauf36bcf6a2020-02-03 15:12:52 -0700278 access_state.ApplyExecutionBarrier(src_exec_scope, dst_exec_scope);
John Zulauf9cb530d2019-09-30 14:14:10 -0600279
280 for (const auto &functor : barrier_functor) {
281 functor(accesses, pos);
282 }
283 return pos;
284 }
285
John Zulauf36bcf6a2020-02-03 15:12:52 -0700286 ApplyGlobalBarrierFunctor(VkPipelineStageFlags src_exec_scope, VkPipelineStageFlags dst_exec_scope,
287 SyncStageAccessFlags src_stage_accesses, SyncStageAccessFlags dst_stage_accesses,
John Zulauf9cb530d2019-09-30 14:14:10 -0600288 uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers)
John Zulauf36bcf6a2020-02-03 15:12:52 -0700289 : src_exec_scope(src_exec_scope), dst_exec_scope(dst_exec_scope) {
John Zulauf9cb530d2019-09-30 14:14:10 -0600290 // Don't want to create this per tracked item, but don't want to loop through all tracked items per barrier...
291 barrier_functor.reserve(memoryBarrierCount);
292 for (uint32_t barrier_index = 0; barrier_index < memoryBarrierCount; barrier_index++) {
293 const auto &barrier = pMemoryBarriers[barrier_index];
John Zulauf36bcf6a2020-02-03 15:12:52 -0700294 barrier_functor.emplace_back(src_exec_scope, SyncStageAccess::AccessScope(src_stage_accesses, barrier.srcAccessMask),
295 dst_exec_scope, SyncStageAccess::AccessScope(dst_stage_accesses, barrier.dstAccessMask));
John Zulauf9cb530d2019-09-30 14:14:10 -0600296 }
297 }
298
John Zulauf36bcf6a2020-02-03 15:12:52 -0700299 const VkPipelineStageFlags src_exec_scope;
300 const VkPipelineStageFlags dst_exec_scope;
John Zulauf9cb530d2019-09-30 14:14:10 -0600301 std::vector<ApplyMemoryAccessBarrierFunctor> barrier_functor;
302};
303
John Zulauf5c5e88d2019-12-26 11:22:02 -0700304void UpdateAccessState(ResourceAccessRangeMap *accesses, SyncStageAccessIndex current_usage, const ResourceAccessRange &range,
305 const ResourceUsageTag &tag) {
306 UpdateMemoryAccessStateFunctor action(current_usage, tag);
307 UpdateMemoryAccessState(accesses, range, action);
308}
309
310void UpdateAccessState(const IMAGE_STATE &image, ResourceAccessRangeMap *accesses, SyncStageAccessIndex current_usage,
311 const VkImageSubresourceLayers &subresource, const VkOffset3D &offset, const VkExtent3D &extent,
312 const ResourceUsageTag &tag) {
313 // TODO: replace the encoder/generator with offset3D aware versions
314 VkImageSubresourceRange subresource_range = {subresource.aspectMask, subresource.mipLevel, 1, subresource.baseArrayLayer,
315 subresource.layerCount};
316 subresource_adapter::RangeGenerator range_gen(image.range_encoder, subresource_range);
317 for (; range_gen->non_empty(); ++range_gen) {
318 UpdateAccessState(accesses, current_usage, *range_gen, tag);
319 }
320}
321
John Zulauf9cb530d2019-09-30 14:14:10 -0600322HazardResult ResourceAccessState::DetectHazard(SyncStageAccessIndex usage_index) const {
323 HazardResult hazard;
324 auto usage = FlagBit(usage_index);
325 if (IsRead(usage)) {
326 if (IsWriteHazard(usage)) {
327 hazard.Set(READ_AFTER_WRITE, write_tag);
328 }
329 } else {
330 // Assume write
331 // TODO determine what to do with READ-WRITE usage states if any
332 // Write-After-Write check -- if we have a previous write to test against
333 if (last_write && IsWriteHazard(usage)) {
334 hazard.Set(WRITE_AFTER_WRITE, write_tag);
335 } else {
336 // Only look for casus belli for WAR
337 const auto usage_stage = PipelineStageBit(usage_index);
338 for (uint32_t read_index = 0; read_index < last_read_count; read_index++) {
339 if (IsReadHazard(usage_stage, last_reads[read_index])) {
340 hazard.Set(WRITE_AFTER_READ, last_reads[read_index].tag);
341 break;
342 }
343 }
344 }
345 }
346 return hazard;
347}
348
John Zulauf36bcf6a2020-02-03 15:12:52 -0700349HazardResult ResourceAccessState::DetectBarrierHazard(SyncStageAccessIndex usage_index, VkPipelineStageFlags src_exec_scope,
350 SyncStageAccessFlags src_access_scope) const {
John Zulauf0cb5be22020-01-23 12:18:22 -0700351 // Only supporting image layout transitions for now
352 assert(usage_index == SyncStageAccessIndex::SYNC_IMAGE_LAYOUT_TRANSITION);
353 HazardResult hazard;
354 if (last_write) {
355 // If the previous write is *not* in the 1st access scope
356 // *AND* the current barrier is not in the dependency chain
357 // *AND* the there is no prior memory barrier for the previous write in the dependency chain
358 // then the barrier access is unsafe (R/W after W)
John Zulauf36bcf6a2020-02-03 15:12:52 -0700359 if (((last_write & src_access_scope) == 0) && ((src_exec_scope & write_dependency_chain) == 0) && (write_barriers == 0)) {
John Zulauf0cb5be22020-01-23 12:18:22 -0700360 // TODO: Do we need a difference hazard name for this?
361 hazard.Set(WRITE_AFTER_WRITE, write_tag);
362 }
363 } else {
364 // Look at the reads
365 for (uint32_t read_index = 0; read_index < last_read_count; read_index++) {
John Zulauf36bcf6a2020-02-03 15:12:52 -0700366 const auto &read_access = last_reads[read_index];
367 // If the read stage is not in the src sync sync
368 // *AND* not execution chained with an existing sync barrier (that's the or)
369 // then the barrier access is unsafe (R/W after R)
370 if ((src_exec_scope & (read_access.stage | read_access.barriers)) == 0) {
371 hazard.Set(WRITE_AFTER_READ, read_access.tag);
John Zulauf0cb5be22020-01-23 12:18:22 -0700372 break;
373 }
374 }
375 }
376 return hazard;
377}
378
John Zulauf9cb530d2019-09-30 14:14:10 -0600379void ResourceAccessState::Update(SyncStageAccessIndex usage_index, const ResourceUsageTag &tag) {
380 // Move this logic in the ResourceStateTracker as methods, thereof (or we'll repeat it for every flavor of resource...
381 const auto usage_bit = FlagBit(usage_index);
382 if (IsRead(usage_index)) {
383 // Mulitple outstanding reads may be of interest and do dependency chains independently
384 // However, for purposes of barrier tracking, only one read per pipeline stage matters
385 const auto usage_stage = PipelineStageBit(usage_index);
386 if (usage_stage & last_read_stages) {
387 for (uint32_t read_index = 0; read_index < last_read_count; read_index++) {
388 ReadState &access = last_reads[read_index];
389 if (access.stage == usage_stage) {
390 access.barriers = 0;
391 access.tag = tag;
392 break;
393 }
394 }
395 } else {
396 // We don't have this stage in the list yet...
397 assert(last_read_count < last_reads.size());
398 ReadState &access = last_reads[last_read_count++];
399 access.stage = usage_stage;
400 access.barriers = 0;
401 access.tag = tag;
402 last_read_stages |= usage_stage;
403 }
404 } else {
405 // Assume write
406 // TODO determine what to do with READ-WRITE operations if any
407 // Clobber last read and both sets of barriers... because all we have is DANGER, DANGER, WILL ROBINSON!!!
408 // if the last_reads/last_write were unsafe, we've reported them,
409 // in either case the prior access is irrelevant, we can overwrite them as *this* write is now after them
410 last_read_count = 0;
411 last_read_stages = 0;
412
413 write_barriers = 0;
414 write_dependency_chain = 0;
415 write_tag = tag;
416 last_write = usage_bit;
417 }
418}
419void ResourceAccessState::ApplyExecutionBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask) {
420 // Execution Barriers only protect read operations
421 for (uint32_t read_index = 0; read_index < last_read_count; read_index++) {
422 ReadState &access = last_reads[read_index];
423 // The | implements the "dependency chain" logic for this access, as the barriers field stores the second sync scope
424 if (srcStageMask & (access.stage | access.barriers)) {
425 access.barriers |= dstStageMask;
426 }
427 }
428 if (write_dependency_chain & srcStageMask) write_dependency_chain |= dstStageMask;
429}
430
John Zulauf36bcf6a2020-02-03 15:12:52 -0700431void ResourceAccessState::ApplyMemoryAccessBarrier(VkPipelineStageFlags src_exec_scope, SyncStageAccessFlags src_access_scope,
432 VkPipelineStageFlags dst_exec_scope, SyncStageAccessFlags dst_access_scope) {
John Zulauf9cb530d2019-09-30 14:14:10 -0600433 // Assuming we've applied the execution side of this barrier, we update just the write
434 // The || implements the "dependency chain" logic for this barrier
John Zulauf36bcf6a2020-02-03 15:12:52 -0700435 if ((src_access_scope & last_write) || (write_dependency_chain & src_exec_scope)) {
436 write_barriers |= dst_access_scope;
437 write_dependency_chain |= dst_exec_scope;
John Zulauf9cb530d2019-09-30 14:14:10 -0600438 }
439}
440
441void SyncValidator::ResetCommandBuffer(VkCommandBuffer command_buffer) {
442 auto *tracker = GetAccessTrackerNoInsert(command_buffer);
443 if (tracker) {
444 tracker->Reset();
445 }
446}
447
John Zulauf5c5e88d2019-12-26 11:22:02 -0700448void SyncValidator::ApplyGlobalBarriers(ResourceAccessTracker *tracker, VkPipelineStageFlags srcStageMask,
John Zulauf36bcf6a2020-02-03 15:12:52 -0700449 VkPipelineStageFlags dstStageMask, SyncStageAccessFlags src_access_scope,
450 SyncStageAccessFlags dst_access_scope, uint32_t memoryBarrierCount,
John Zulauf9cb530d2019-09-30 14:14:10 -0600451 const VkMemoryBarrier *pMemoryBarriers) {
452 // TODO: Implement this better (maybe some delayed/on-demand integration).
John Zulauf36bcf6a2020-02-03 15:12:52 -0700453 ApplyGlobalBarrierFunctor barriers_functor(srcStageMask, dstStageMask, src_access_scope, dst_access_scope, memoryBarrierCount,
John Zulauf9cb530d2019-09-30 14:14:10 -0600454 pMemoryBarriers);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700455 for (auto &mem_access_pair : tracker->GetMemoryAccessMap()) {
John Zulauf9cb530d2019-09-30 14:14:10 -0600456 UpdateMemoryAccessState(&mem_access_pair.second, full_range, barriers_functor);
457 }
John Zulauf5c5e88d2019-12-26 11:22:02 -0700458 for (auto &image_access_pair : tracker->GetImageAccessMap()) {
459 UpdateMemoryAccessState(&image_access_pair.second, full_range, barriers_functor);
460 }
John Zulauf9cb530d2019-09-30 14:14:10 -0600461}
462
John Zulauf36bcf6a2020-02-03 15:12:52 -0700463void SyncValidator::ApplyBufferBarriers(ResourceAccessTracker *tracker, VkPipelineStageFlags src_exec_scope,
464 SyncStageAccessFlags src_stage_accesses, VkPipelineStageFlags dst_exec_scope,
465 SyncStageAccessFlags dst_stage_accesses, uint32_t barrier_count,
John Zulauf9cb530d2019-09-30 14:14:10 -0600466 const VkBufferMemoryBarrier *barriers) {
467 // TODO Implement this at subresource/memory_range accuracy
468 for (uint32_t index = 0; index < barrier_count; index++) {
469 const auto &barrier = barriers[index];
470 const auto *buffer = Get<BUFFER_STATE>(barrier.buffer);
471 if (!buffer) continue;
John Zulauf5c5e88d2019-12-26 11:22:02 -0700472 auto *accesses = tracker->GetMemoryAccessesNoInsert(buffer->binding.mem_state->mem);
John Zulauf9cb530d2019-09-30 14:14:10 -0600473 if (!accesses) continue;
John Zulauf5c5e88d2019-12-26 11:22:02 -0700474 ResourceAccessRange range = MakeMemoryAccessRange(*buffer, barrier.offset, barrier.size);
John Zulauf9cb530d2019-09-30 14:14:10 -0600475 UpdateMemoryAccessState(
476 accesses, range,
John Zulauf36bcf6a2020-02-03 15:12:52 -0700477 ApplyMemoryAccessBarrierFunctor(src_exec_scope, AccessScope(src_stage_accesses, barrier.srcAccessMask), dst_exec_scope,
478 AccessScope(dst_stage_accesses, barrier.dstAccessMask)));
John Zulauf9cb530d2019-09-30 14:14:10 -0600479 }
480}
481
John Zulauf36bcf6a2020-02-03 15:12:52 -0700482void SyncValidator::ApplyImageBarriers(ResourceAccessTracker *tracker, VkPipelineStageFlags src_exec_scope,
483 SyncStageAccessFlags src_stage_accesses, VkPipelineStageFlags dst_exec_scope,
484 SyncStageAccessFlags dst_stage_accesses, uint32_t barrier_count,
John Zulauf5c5e88d2019-12-26 11:22:02 -0700485 const VkImageMemoryBarrier *barriers) {
486 for (uint32_t index = 0; index < barrier_count; index++) {
487 const auto &barrier = barriers[index];
488 const auto *image = Get<IMAGE_STATE>(barrier.image);
489 if (!image) continue;
490 auto *accesses = tracker->GetImageAccessesNoInsert(image->image);
491 if (!accesses) continue;
492 auto subresource_range = NormalizeSubresourceRange(image->createInfo, barrier.subresourceRange);
493 subresource_adapter::RangeGenerator range_gen(image->range_encoder, subresource_range);
John Zulauf36bcf6a2020-02-03 15:12:52 -0700494 const ApplyMemoryAccessBarrierFunctor barrier_action(src_exec_scope, AccessScope(src_stage_accesses, barrier.srcAccessMask),
495 dst_exec_scope,
496 AccessScope(dst_stage_accesses, barrier.dstAccessMask));
John Zulauf5c5e88d2019-12-26 11:22:02 -0700497 for (; range_gen->non_empty(); ++range_gen) {
498 UpdateMemoryAccessState(accesses, *range_gen, barrier_action);
499 }
John Zulauf9cb530d2019-09-30 14:14:10 -0600500 }
John Zulauf9cb530d2019-09-30 14:14:10 -0600501}
502
503bool SyncValidator::PreCallValidateCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
504 uint32_t regionCount, const VkBufferCopy *pRegions) const {
505 bool skip = false;
506 const auto *const const_this = this;
507 const auto *tracker = const_this->GetAccessTracker(commandBuffer);
508 if (tracker) {
509 // If we have no previous accesses, we have no hazards
510 // TODO: make this sub-resource capable
511 // TODO: make this general, and stuff it into templates/utility functions
512 const auto *src_buffer = Get<BUFFER_STATE>(srcBuffer);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700513 const auto src_access =
514 (src_buffer && !src_buffer->sparse) ? tracker->GetMemoryAccesses(src_buffer->binding.mem_state->mem) : nullptr;
John Zulauf9cb530d2019-09-30 14:14:10 -0600515 const auto *dst_buffer = Get<BUFFER_STATE>(dstBuffer);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700516 const auto dst_access =
517 (dst_buffer && !dst_buffer->sparse) ? tracker->GetMemoryAccesses(dst_buffer->binding.mem_state->mem) : nullptr;
John Zulauf9cb530d2019-09-30 14:14:10 -0600518
519 for (uint32_t region = 0; region < regionCount; region++) {
520 const auto &copy_region = pRegions[region];
521 if (src_access) {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700522 ResourceAccessRange src_range = MakeMemoryAccessRange(*src_buffer, copy_region.srcOffset, copy_region.size);
John Zulauf9cb530d2019-09-30 14:14:10 -0600523 auto hazard = DetectHazard(*src_access, SYNC_TRANSFER_TRANSFER_READ, src_range);
524 if (hazard.hazard) {
525 // TODO -- add tag information to log msg when useful.
526 skip |= LogError(srcBuffer, string_SyncHazardVUID(hazard.hazard), "Hazard %s for srcBuffer %s, region %" PRIu32,
527 string_SyncHazard(hazard.hazard), report_data->FormatHandle(srcBuffer).c_str(), region);
528 }
529 }
530 if (dst_access && !skip) {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700531 ResourceAccessRange dst_range = MakeMemoryAccessRange(*dst_buffer, copy_region.dstOffset, copy_region.size);
John Zulauf9cb530d2019-09-30 14:14:10 -0600532 auto hazard = DetectHazard(*dst_access, SYNC_TRANSFER_TRANSFER_WRITE, dst_range);
533 if (hazard.hazard) {
534 skip |= LogError(dstBuffer, string_SyncHazardVUID(hazard.hazard), "Hazard %s for dstBuffer %s, region %" PRIu32,
535 string_SyncHazard(hazard.hazard), report_data->FormatHandle(dstBuffer).c_str(), region);
536 }
537 }
538 if (skip) break;
539 }
540 }
541 return skip;
542}
543
544void SyncValidator::PreCallRecordCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
545 uint32_t regionCount, const VkBufferCopy *pRegions) {
546 auto *tracker = GetAccessTracker(commandBuffer);
547 assert(tracker);
548 const auto *src_buffer = Get<BUFFER_STATE>(srcBuffer);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700549 const auto src_access =
550 (src_buffer && !src_buffer->sparse) ? tracker->GetMemoryAccesses(src_buffer->binding.mem_state->mem) : nullptr;
John Zulauf9cb530d2019-09-30 14:14:10 -0600551 const auto *dst_buffer = Get<BUFFER_STATE>(dstBuffer);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700552 const auto dst_access =
553 (dst_buffer && !dst_buffer->sparse) ? tracker->GetMemoryAccesses(dst_buffer->binding.mem_state->mem) : nullptr;
John Zulauf9cb530d2019-09-30 14:14:10 -0600554
555 for (uint32_t region = 0; region < regionCount; region++) {
556 const auto &copy_region = pRegions[region];
557 if (src_access) {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700558 ResourceAccessRange src_range = MakeMemoryAccessRange(*src_buffer, copy_region.srcOffset, copy_region.size);
559 UpdateAccessState(src_access, SYNC_TRANSFER_TRANSFER_READ, src_range, tag);
John Zulauf9cb530d2019-09-30 14:14:10 -0600560 }
561 if (dst_access) {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700562 ResourceAccessRange dst_range = MakeMemoryAccessRange(*dst_buffer, copy_region.dstOffset, copy_region.size);
563 UpdateAccessState(dst_access, SYNC_TRANSFER_TRANSFER_WRITE, dst_range, tag);
564 }
565 }
566}
567
568bool SyncValidator::PreCallValidateCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
569 VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
570 const VkImageCopy *pRegions) const {
571 bool skip = false;
572 auto *tracker = GetAccessTracker(commandBuffer);
573 if (tracker) {
574 const auto *src_image = Get<IMAGE_STATE>(srcImage);
575 const auto src_access = tracker->GetImageAccesses(srcImage);
576 const auto *dst_image = Get<IMAGE_STATE>(dstImage);
577 const auto dst_access = tracker->GetImageAccesses(dstImage);
578
579 for (uint32_t region = 0; region < regionCount; region++) {
580 const auto &copy_region = pRegions[region];
581 if (src_access) {
582 auto hazard = DetectHazard(*src_image, *src_access, SYNC_TRANSFER_TRANSFER_READ, copy_region.srcSubresource,
583 copy_region.srcOffset, copy_region.extent);
584 if (hazard.hazard) {
585 skip |= LogError(srcImage, string_SyncHazardVUID(hazard.hazard), "Hazard %s for srcImage %s, region %" PRIu32,
586 string_SyncHazard(hazard.hazard), report_data->FormatHandle(srcImage).c_str(), region);
587 }
588 }
589 if (dst_access) {
590 auto hazard = DetectHazard(*dst_image, *dst_access, SYNC_TRANSFER_TRANSFER_WRITE, copy_region.dstSubresource,
591 copy_region.dstOffset, copy_region.extent);
592 if (hazard.hazard) {
593 skip |= LogError(dstImage, string_SyncHazardVUID(hazard.hazard), "Hazard %s for dstImage %s, region %" PRIu32,
594 string_SyncHazard(hazard.hazard), report_data->FormatHandle(dstImage).c_str(), region);
595 }
596 }
597 }
598 }
599 return skip;
600}
601
602void SyncValidator::PreCallRecordCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
603 VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
604 const VkImageCopy *pRegions) {
605 auto *tracker = GetAccessTracker(commandBuffer);
606 assert(tracker);
607 auto *src_image = Get<IMAGE_STATE>(srcImage);
608 auto src_access = tracker->GetImageAccesses(srcImage);
609 auto *dst_image = Get<IMAGE_STATE>(dstImage);
610 auto dst_access = tracker->GetImageAccesses(dstImage);
611
612 for (uint32_t region = 0; region < regionCount; region++) {
613 const auto &copy_region = pRegions[region];
614 if (src_access) {
615 UpdateAccessState(*src_image, src_access, SYNC_TRANSFER_TRANSFER_READ, copy_region.srcSubresource,
616 copy_region.srcOffset, copy_region.extent, tag);
617 }
618 if (dst_access) {
619 UpdateAccessState(*dst_image, dst_access, SYNC_TRANSFER_TRANSFER_WRITE, copy_region.dstSubresource,
620 copy_region.dstOffset, copy_region.extent, tag);
John Zulauf9cb530d2019-09-30 14:14:10 -0600621 }
622 }
623}
624
625bool SyncValidator::PreCallValidateCmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask,
626 VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags,
627 uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
628 uint32_t bufferMemoryBarrierCount,
629 const VkBufferMemoryBarrier *pBufferMemoryBarriers,
630 uint32_t imageMemoryBarrierCount,
631 const VkImageMemoryBarrier *pImageMemoryBarriers) const {
632 bool skip = false;
John Zulauf0cb5be22020-01-23 12:18:22 -0700633 const auto *tracker = GetAccessTracker(commandBuffer);
634 if (!tracker) return skip;
635
636 const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
637 assert(cb_state);
638 if (!cb_state) return skip;
639
640 const auto src_stage_mask = ExpandPipelineStages(GetQueueFlags(*cb_state), srcStageMask);
John Zulauf36bcf6a2020-02-03 15:12:52 -0700641 const auto src_exec_scope = WithEarlierPipelineStages(src_stage_mask);
642 auto src_stage_accesses = AccessScopeByStage(src_stage_mask);
John Zulauf0cb5be22020-01-23 12:18:22 -0700643 // Validate Image Layout transitions
644 for (uint32_t index = 0; index < imageMemoryBarrierCount; index++) {
645 const auto &barrier = pImageMemoryBarriers[index];
646 if (barrier.newLayout == barrier.oldLayout) continue; // Only interested in layout transitions at this point.
647 const auto *image_state = Get<IMAGE_STATE>(barrier.image);
648 if (!image_state) continue;
John Zulauf36bcf6a2020-02-03 15:12:52 -0700649 const auto hazard = DetectImageBarrierHazard(*tracker, *image_state, src_exec_scope, src_stage_accesses, barrier);
John Zulauf0cb5be22020-01-23 12:18:22 -0700650 if (hazard.hazard) {
651 // TODO -- add tag information to log msg when useful.
652 skip |= LogError(barrier.image, string_SyncHazardVUID(hazard.hazard), "Hazard %s for image barrier %" PRIu32 " %s",
653 string_SyncHazard(hazard.hazard), index, report_data->FormatHandle(barrier.image).c_str());
654 }
655 }
John Zulauf9cb530d2019-09-30 14:14:10 -0600656
657 return skip;
658}
659
660void SyncValidator::PreCallRecordCmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask,
661 VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags,
662 uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
663 uint32_t bufferMemoryBarrierCount,
664 const VkBufferMemoryBarrier *pBufferMemoryBarriers,
665 uint32_t imageMemoryBarrierCount,
666 const VkImageMemoryBarrier *pImageMemoryBarriers) {
667 // Just implement the buffer barrier for now
668 auto *tracker = GetAccessTracker(commandBuffer);
669 assert(tracker);
John Zulauf9cb530d2019-09-30 14:14:10 -0600670
John Zulauf0cb5be22020-01-23 12:18:22 -0700671 const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
672 assert(cb_state);
673 if (!cb_state) return;
674
675 const auto src_stage_mask = ExpandPipelineStages(GetQueueFlags(*cb_state), srcStageMask);
John Zulauf36bcf6a2020-02-03 15:12:52 -0700676 auto src_stage_accesses = AccessScopeByStage(src_stage_mask);
John Zulauf0cb5be22020-01-23 12:18:22 -0700677 const auto dst_stage_mask = ExpandPipelineStages(GetQueueFlags(*cb_state), dstStageMask);
John Zulauf36bcf6a2020-02-03 15:12:52 -0700678 auto dst_stage_accesses = AccessScopeByStage(dst_stage_mask);
679 const auto src_exec_scope = WithEarlierPipelineStages(src_stage_mask);
680 const auto dst_exec_scope = WithLaterPipelineStages(dst_stage_mask);
681 ApplyBufferBarriers(tracker, src_exec_scope, src_stage_accesses, dst_exec_scope, dst_stage_accesses, bufferMemoryBarrierCount,
John Zulauf9cb530d2019-09-30 14:14:10 -0600682 pBufferMemoryBarriers);
John Zulauf36bcf6a2020-02-03 15:12:52 -0700683 ApplyImageBarriers(tracker, src_exec_scope, src_stage_accesses, dst_exec_scope, dst_stage_accesses, imageMemoryBarrierCount,
John Zulauf5c5e88d2019-12-26 11:22:02 -0700684 pImageMemoryBarriers);
John Zulauf9cb530d2019-09-30 14:14:10 -0600685
686 // Apply these last in-case there operation is a superset of the other two and would clean them up...
John Zulauf36bcf6a2020-02-03 15:12:52 -0700687 ApplyGlobalBarriers(tracker, src_exec_scope, dst_exec_scope, src_stage_accesses, dst_stage_accesses, memoryBarrierCount,
John Zulauf0cb5be22020-01-23 12:18:22 -0700688 pMemoryBarriers);
John Zulauf9cb530d2019-09-30 14:14:10 -0600689}
690
691void SyncValidator::PostCallRecordCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo,
692 const VkAllocationCallbacks *pAllocator, VkDevice *pDevice, VkResult result) {
693 // The state tracker sets up the device state
694 StateTracker::PostCallRecordCreateDevice(gpu, pCreateInfo, pAllocator, pDevice, result);
695
696 // Add the callback hooks for the functions that are either broadly or deeply used and that the ValidationStateTracker refactor
697 // would be messier without.
698 // TODO: Find a good way to do this hooklessly.
699 ValidationObject *device_object = GetLayerDataPtr(get_dispatch_key(*pDevice), layer_data_map);
700 ValidationObject *validation_data = GetValidationObject(device_object->object_dispatch, LayerObjectTypeSyncValidation);
701 SyncValidator *sync_device_state = static_cast<SyncValidator *>(validation_data);
702
703 sync_device_state->SetCommandBufferResetCallback(
704 [sync_device_state](VkCommandBuffer command_buffer) -> void { sync_device_state->ResetCommandBuffer(command_buffer); });
705}