blob: 077d38224749edd74609aeaff9d0bc8cc6b7604a [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
130HazardResult DetectHazard(const ResourceAccessRangeMap &accesses, SyncStageAccessIndex current_usage,
131 const ResourceAccessRange &range) {
132 const auto from = accesses.lower_bound(range);
133 const auto to = accesses.upper_bound(range);
134 for (auto pos = from; pos != to; ++pos) {
135 const auto &access_state = pos->second;
136 HazardResult hazard = access_state.DetectHazard(current_usage);
137 if (hazard.hazard) return hazard;
138 }
139 return HazardResult();
140}
141
142HazardResult DetectHazard(const IMAGE_STATE &image, const ResourceAccessRangeMap &accesses, SyncStageAccessIndex current_usage,
143 const VkImageSubresourceLayers &subresource, const VkOffset3D &offset, const VkExtent3D &extent) {
144 // TODO: replace the encoder/generator with offset3D/extent3D aware versions
145 VkImageSubresourceRange subresource_range = {subresource.aspectMask, subresource.mipLevel, 1, subresource.baseArrayLayer,
146 subresource.layerCount};
147 subresource_adapter::RangeGenerator range_gen(image.range_encoder, subresource_range);
148 for (; range_gen->non_empty(); ++range_gen) {
149 HazardResult hazard = DetectHazard(accesses, current_usage, *range_gen);
150 if (hazard.hazard) return hazard;
151 }
152 return HazardResult();
John Zulauf9cb530d2019-09-30 14:14:10 -0600153}
154
John Zulauf0cb5be22020-01-23 12:18:22 -0700155HazardResult DetectBarrierHazard(const ResourceAccessRangeMap &accesses, SyncStageAccessIndex current_usage,
John Zulauf36bcf6a2020-02-03 15:12:52 -0700156 VkPipelineStageFlags src_exec_scope, SyncStageAccessFlags src_access_scope,
John Zulauf0cb5be22020-01-23 12:18:22 -0700157 const ResourceAccessRange &range) {
158 const auto from = accesses.lower_bound(range);
159 const auto to = accesses.upper_bound(range);
160 for (auto pos = from; pos != to; ++pos) {
161 const auto &access_state = pos->second;
John Zulauf36bcf6a2020-02-03 15:12:52 -0700162 HazardResult hazard = access_state.DetectBarrierHazard(current_usage, src_exec_scope, src_access_scope);
John Zulauf0cb5be22020-01-23 12:18:22 -0700163 if (hazard.hazard) return hazard;
164 }
165 return HazardResult();
166}
167
168HazardResult DetectImageBarrierHazard(const ResourceAccessTracker &tracker, const IMAGE_STATE &image,
John Zulauf36bcf6a2020-02-03 15:12:52 -0700169 VkPipelineStageFlags src_exec_scope, SyncStageAccessFlags src_stage_accesses,
John Zulauf0cb5be22020-01-23 12:18:22 -0700170 const VkImageMemoryBarrier &barrier) {
171 auto *accesses = tracker.GetImageAccesses(image.image);
172 if (!accesses) return HazardResult();
173
174 auto subresource_range = NormalizeSubresourceRange(image.createInfo, barrier.subresourceRange);
175 subresource_adapter::RangeGenerator range_gen(image.range_encoder, subresource_range);
John Zulauf36bcf6a2020-02-03 15:12:52 -0700176 const auto src_access_scope = SyncStageAccess::AccessScope(src_stage_accesses, barrier.srcAccessMask);
John Zulauf0cb5be22020-01-23 12:18:22 -0700177 for (; range_gen->non_empty(); ++range_gen) {
John Zulauf36bcf6a2020-02-03 15:12:52 -0700178 HazardResult hazard = DetectBarrierHazard(*accesses, SyncStageAccessIndex::SYNC_IMAGE_LAYOUT_TRANSITION, src_exec_scope,
179 src_access_scope, *range_gen);
John Zulauf0cb5be22020-01-23 12:18:22 -0700180 if (hazard.hazard) return hazard;
181 }
182 return HazardResult();
183}
184
John Zulauf9cb530d2019-09-30 14:14:10 -0600185template <typename Flags, typename Map>
186SyncStageAccessFlags AccessScopeImpl(Flags flag_mask, const Map &map) {
187 SyncStageAccessFlags scope = 0;
188 for (const auto &bit_scope : map) {
189 if (flag_mask < bit_scope.first) break;
190
191 if (flag_mask & bit_scope.first) {
192 scope |= bit_scope.second;
193 }
194 }
195 return scope;
196}
197
198SyncStageAccessFlags SyncStageAccess::AccessScopeByStage(VkPipelineStageFlags stages) {
199 return AccessScopeImpl(stages, syncStageAccessMaskByStageBit);
200}
201
202SyncStageAccessFlags SyncStageAccess::AccessScopeByAccess(VkAccessFlags accesses) {
203 return AccessScopeImpl(accesses, syncStageAccessMaskByAccessBit);
204}
205
206// Getting from stage mask and access mask to stage/acess masks is something we need to be good at...
207SyncStageAccessFlags SyncStageAccess::AccessScope(VkPipelineStageFlags stages, VkAccessFlags accesses) {
208 // The access scope is the intersection of all stage/access types possible for the enabled stages and the enables accesses
209 // (after doing a couple factoring of common terms the union of stage/access intersections is the intersections of the
210 // union of all stage/access types for all the stages and the same unions for the access mask...
211 return AccessScopeByStage(stages) & AccessScopeByAccess(accesses);
212}
213
214template <typename Action>
John Zulauf5c5e88d2019-12-26 11:22:02 -0700215void UpdateMemoryAccessState(ResourceAccessRangeMap *accesses, const ResourceAccessRange &range, const Action &action) {
John Zulauf9cb530d2019-09-30 14:14:10 -0600216 // TODO -- region/mem-range accuracte update
217 auto pos = accesses->lower_bound(range);
218 if (pos == accesses->end() || !pos->first.intersects(range)) {
219 // The range is empty, fill it with a default value.
220 pos = action.Infill(accesses, pos, range);
221 } else if (range.begin < pos->first.begin) {
222 // Leading empty space, infill
John Zulauf5c5e88d2019-12-26 11:22:02 -0700223 pos = action.Infill(accesses, pos, ResourceAccessRange(range.begin, pos->first.begin));
John Zulauf9cb530d2019-09-30 14:14:10 -0600224 } else if (pos->first.begin < range.begin) {
225 // Trim the beginning if needed
226 pos = accesses->split(pos, range.begin, sparse_container::split_op_keep_both());
227 ++pos;
228 }
229
230 const auto the_end = accesses->end();
231 while ((pos != the_end) && pos->first.intersects(range)) {
232 if (pos->first.end > range.end) {
233 pos = accesses->split(pos, range.end, sparse_container::split_op_keep_both());
234 }
235
236 pos = action(accesses, pos);
237 if (pos == the_end) break;
238
239 auto next = pos;
240 ++next;
241 if ((pos->first.end < range.end) && (next != the_end) && !next->first.is_subsequent_to(pos->first)) {
242 // Need to infill if next is disjoint
243 VkDeviceSize limit = (next == the_end) ? range.end : std::min(range.end, next->first.begin);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700244 ResourceAccessRange new_range(pos->first.end, limit);
John Zulauf9cb530d2019-09-30 14:14:10 -0600245 next = action.Infill(accesses, next, new_range);
246 }
247 pos = next;
248 }
249}
250
251struct UpdateMemoryAccessStateFunctor {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700252 using Iterator = ResourceAccessRangeMap::iterator;
253 Iterator Infill(ResourceAccessRangeMap *accesses, Iterator pos, ResourceAccessRange range) const {
John Zulauf9cb530d2019-09-30 14:14:10 -0600254 return accesses->insert(pos, std::make_pair(range, ResourceAccessState()));
255 }
John Zulauf5c5e88d2019-12-26 11:22:02 -0700256 Iterator operator()(ResourceAccessRangeMap *accesses, Iterator pos) const {
John Zulauf9cb530d2019-09-30 14:14:10 -0600257 auto &access_state = pos->second;
258 access_state.Update(usage, tag);
259 return pos;
260 }
261
262 UpdateMemoryAccessStateFunctor(SyncStageAccessIndex usage_, const ResourceUsageTag &tag_) : usage(usage_), tag(tag_) {}
263 SyncStageAccessIndex usage;
264 const ResourceUsageTag &tag;
265};
266
267struct ApplyMemoryAccessBarrierFunctor {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700268 using Iterator = ResourceAccessRangeMap::iterator;
269 inline Iterator Infill(ResourceAccessRangeMap *accesses, Iterator pos, ResourceAccessRange range) const { return pos; }
John Zulauf9cb530d2019-09-30 14:14:10 -0600270
John Zulauf5c5e88d2019-12-26 11:22:02 -0700271 Iterator operator()(ResourceAccessRangeMap *accesses, Iterator pos) const {
John Zulauf9cb530d2019-09-30 14:14:10 -0600272 auto &access_state = pos->second;
John Zulauf36bcf6a2020-02-03 15:12:52 -0700273 access_state.ApplyMemoryAccessBarrier(src_exec_scope, src_access_scope, dst_exec_scope, dst_access_scope);
John Zulauf9cb530d2019-09-30 14:14:10 -0600274 return pos;
275 }
276
John Zulauf36bcf6a2020-02-03 15:12:52 -0700277 ApplyMemoryAccessBarrierFunctor(VkPipelineStageFlags src_exec_scope_, SyncStageAccessFlags src_access_scope_,
278 VkPipelineStageFlags dst_exec_scope_, SyncStageAccessFlags dst_access_scope_)
279 : src_exec_scope(src_exec_scope_),
280 src_access_scope(src_access_scope_),
281 dst_exec_scope(dst_exec_scope_),
282 dst_access_scope(dst_access_scope_) {}
John Zulauf9cb530d2019-09-30 14:14:10 -0600283
John Zulauf36bcf6a2020-02-03 15:12:52 -0700284 VkPipelineStageFlags src_exec_scope;
285 SyncStageAccessFlags src_access_scope;
286 VkPipelineStageFlags dst_exec_scope;
287 SyncStageAccessFlags dst_access_scope;
John Zulauf9cb530d2019-09-30 14:14:10 -0600288};
289
290struct ApplyGlobalBarrierFunctor {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700291 using Iterator = ResourceAccessRangeMap::iterator;
292 inline Iterator Infill(ResourceAccessRangeMap *accesses, Iterator pos, ResourceAccessRange range) const { return pos; }
John Zulauf9cb530d2019-09-30 14:14:10 -0600293
John Zulauf5c5e88d2019-12-26 11:22:02 -0700294 Iterator operator()(ResourceAccessRangeMap *accesses, Iterator pos) const {
John Zulauf9cb530d2019-09-30 14:14:10 -0600295 auto &access_state = pos->second;
John Zulauf36bcf6a2020-02-03 15:12:52 -0700296 access_state.ApplyExecutionBarrier(src_exec_scope, dst_exec_scope);
John Zulauf9cb530d2019-09-30 14:14:10 -0600297
298 for (const auto &functor : barrier_functor) {
299 functor(accesses, pos);
300 }
301 return pos;
302 }
303
John Zulauf36bcf6a2020-02-03 15:12:52 -0700304 ApplyGlobalBarrierFunctor(VkPipelineStageFlags src_exec_scope, VkPipelineStageFlags dst_exec_scope,
305 SyncStageAccessFlags src_stage_accesses, SyncStageAccessFlags dst_stage_accesses,
John Zulauf9cb530d2019-09-30 14:14:10 -0600306 uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers)
John Zulauf36bcf6a2020-02-03 15:12:52 -0700307 : src_exec_scope(src_exec_scope), dst_exec_scope(dst_exec_scope) {
John Zulauf9cb530d2019-09-30 14:14:10 -0600308 // Don't want to create this per tracked item, but don't want to loop through all tracked items per barrier...
309 barrier_functor.reserve(memoryBarrierCount);
310 for (uint32_t barrier_index = 0; barrier_index < memoryBarrierCount; barrier_index++) {
311 const auto &barrier = pMemoryBarriers[barrier_index];
John Zulauf36bcf6a2020-02-03 15:12:52 -0700312 barrier_functor.emplace_back(src_exec_scope, SyncStageAccess::AccessScope(src_stage_accesses, barrier.srcAccessMask),
313 dst_exec_scope, SyncStageAccess::AccessScope(dst_stage_accesses, barrier.dstAccessMask));
John Zulauf9cb530d2019-09-30 14:14:10 -0600314 }
315 }
316
John Zulauf36bcf6a2020-02-03 15:12:52 -0700317 const VkPipelineStageFlags src_exec_scope;
318 const VkPipelineStageFlags dst_exec_scope;
John Zulauf9cb530d2019-09-30 14:14:10 -0600319 std::vector<ApplyMemoryAccessBarrierFunctor> barrier_functor;
320};
321
John Zulauf5c5e88d2019-12-26 11:22:02 -0700322void UpdateAccessState(ResourceAccessRangeMap *accesses, SyncStageAccessIndex current_usage, const ResourceAccessRange &range,
323 const ResourceUsageTag &tag) {
324 UpdateMemoryAccessStateFunctor action(current_usage, tag);
325 UpdateMemoryAccessState(accesses, range, action);
326}
327
328void UpdateAccessState(const IMAGE_STATE &image, ResourceAccessRangeMap *accesses, SyncStageAccessIndex current_usage,
329 const VkImageSubresourceLayers &subresource, const VkOffset3D &offset, const VkExtent3D &extent,
330 const ResourceUsageTag &tag) {
331 // TODO: replace the encoder/generator with offset3D aware versions
332 VkImageSubresourceRange subresource_range = {subresource.aspectMask, subresource.mipLevel, 1, subresource.baseArrayLayer,
333 subresource.layerCount};
334 subresource_adapter::RangeGenerator range_gen(image.range_encoder, subresource_range);
335 for (; range_gen->non_empty(); ++range_gen) {
336 UpdateAccessState(accesses, current_usage, *range_gen, tag);
337 }
338}
339
John Zulauf9cb530d2019-09-30 14:14:10 -0600340HazardResult ResourceAccessState::DetectHazard(SyncStageAccessIndex usage_index) const {
341 HazardResult hazard;
342 auto usage = FlagBit(usage_index);
343 if (IsRead(usage)) {
344 if (IsWriteHazard(usage)) {
345 hazard.Set(READ_AFTER_WRITE, write_tag);
346 }
347 } else {
348 // Assume write
349 // TODO determine what to do with READ-WRITE usage states if any
350 // Write-After-Write check -- if we have a previous write to test against
351 if (last_write && IsWriteHazard(usage)) {
352 hazard.Set(WRITE_AFTER_WRITE, write_tag);
353 } else {
354 // Only look for casus belli for WAR
355 const auto usage_stage = PipelineStageBit(usage_index);
356 for (uint32_t read_index = 0; read_index < last_read_count; read_index++) {
357 if (IsReadHazard(usage_stage, last_reads[read_index])) {
358 hazard.Set(WRITE_AFTER_READ, last_reads[read_index].tag);
359 break;
360 }
361 }
362 }
363 }
364 return hazard;
365}
366
John Zulauf2f952d22020-02-10 11:34:51 -0700367// Asynchronous Hazards occur between subpasses with no connection through the DAG
368HazardResult ResourceAccessState::DetectAsynchronousHazard(SyncStageAccessIndex usage_index) const {
369 HazardResult hazard;
370 auto usage = FlagBit(usage_index);
371 if (IsRead(usage)) {
372 if (last_write != 0) {
373 hazard.Set(READ_RACING_WRITE, write_tag);
374 }
375 } else {
376 if (last_write != 0) {
377 hazard.Set(WRITE_RACING_WRITE, write_tag);
378 } else if (last_read_count > 0) {
379 hazard.Set(WRITE_RACING_READ, last_reads[0].tag);
380 }
381 }
382 return hazard;
383}
384
John Zulauf36bcf6a2020-02-03 15:12:52 -0700385HazardResult ResourceAccessState::DetectBarrierHazard(SyncStageAccessIndex usage_index, VkPipelineStageFlags src_exec_scope,
386 SyncStageAccessFlags src_access_scope) const {
John Zulauf0cb5be22020-01-23 12:18:22 -0700387 // Only supporting image layout transitions for now
388 assert(usage_index == SyncStageAccessIndex::SYNC_IMAGE_LAYOUT_TRANSITION);
389 HazardResult hazard;
390 if (last_write) {
391 // If the previous write is *not* in the 1st access scope
392 // *AND* the current barrier is not in the dependency chain
393 // *AND* the there is no prior memory barrier for the previous write in the dependency chain
394 // then the barrier access is unsafe (R/W after W)
John Zulauf36bcf6a2020-02-03 15:12:52 -0700395 if (((last_write & src_access_scope) == 0) && ((src_exec_scope & write_dependency_chain) == 0) && (write_barriers == 0)) {
John Zulauf0cb5be22020-01-23 12:18:22 -0700396 // TODO: Do we need a difference hazard name for this?
397 hazard.Set(WRITE_AFTER_WRITE, write_tag);
398 }
399 } else {
400 // Look at the reads
401 for (uint32_t read_index = 0; read_index < last_read_count; read_index++) {
John Zulauf36bcf6a2020-02-03 15:12:52 -0700402 const auto &read_access = last_reads[read_index];
403 // If the read stage is not in the src sync sync
404 // *AND* not execution chained with an existing sync barrier (that's the or)
405 // then the barrier access is unsafe (R/W after R)
406 if ((src_exec_scope & (read_access.stage | read_access.barriers)) == 0) {
407 hazard.Set(WRITE_AFTER_READ, read_access.tag);
John Zulauf0cb5be22020-01-23 12:18:22 -0700408 break;
409 }
410 }
411 }
412 return hazard;
413}
414
John Zulauf9cb530d2019-09-30 14:14:10 -0600415void ResourceAccessState::Update(SyncStageAccessIndex usage_index, const ResourceUsageTag &tag) {
416 // Move this logic in the ResourceStateTracker as methods, thereof (or we'll repeat it for every flavor of resource...
417 const auto usage_bit = FlagBit(usage_index);
418 if (IsRead(usage_index)) {
419 // Mulitple outstanding reads may be of interest and do dependency chains independently
420 // However, for purposes of barrier tracking, only one read per pipeline stage matters
421 const auto usage_stage = PipelineStageBit(usage_index);
422 if (usage_stage & last_read_stages) {
423 for (uint32_t read_index = 0; read_index < last_read_count; read_index++) {
424 ReadState &access = last_reads[read_index];
425 if (access.stage == usage_stage) {
426 access.barriers = 0;
427 access.tag = tag;
428 break;
429 }
430 }
431 } else {
432 // We don't have this stage in the list yet...
433 assert(last_read_count < last_reads.size());
434 ReadState &access = last_reads[last_read_count++];
435 access.stage = usage_stage;
436 access.barriers = 0;
437 access.tag = tag;
438 last_read_stages |= usage_stage;
439 }
440 } else {
441 // Assume write
442 // TODO determine what to do with READ-WRITE operations if any
443 // Clobber last read and both sets of barriers... because all we have is DANGER, DANGER, WILL ROBINSON!!!
444 // if the last_reads/last_write were unsafe, we've reported them,
445 // in either case the prior access is irrelevant, we can overwrite them as *this* write is now after them
446 last_read_count = 0;
447 last_read_stages = 0;
448
449 write_barriers = 0;
450 write_dependency_chain = 0;
451 write_tag = tag;
452 last_write = usage_bit;
453 }
454}
455void ResourceAccessState::ApplyExecutionBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask) {
456 // Execution Barriers only protect read operations
457 for (uint32_t read_index = 0; read_index < last_read_count; read_index++) {
458 ReadState &access = last_reads[read_index];
459 // The | implements the "dependency chain" logic for this access, as the barriers field stores the second sync scope
460 if (srcStageMask & (access.stage | access.barriers)) {
461 access.barriers |= dstStageMask;
462 }
463 }
464 if (write_dependency_chain & srcStageMask) write_dependency_chain |= dstStageMask;
465}
466
John Zulauf36bcf6a2020-02-03 15:12:52 -0700467void ResourceAccessState::ApplyMemoryAccessBarrier(VkPipelineStageFlags src_exec_scope, SyncStageAccessFlags src_access_scope,
468 VkPipelineStageFlags dst_exec_scope, SyncStageAccessFlags dst_access_scope) {
John Zulauf9cb530d2019-09-30 14:14:10 -0600469 // Assuming we've applied the execution side of this barrier, we update just the write
470 // The || implements the "dependency chain" logic for this barrier
John Zulauf36bcf6a2020-02-03 15:12:52 -0700471 if ((src_access_scope & last_write) || (write_dependency_chain & src_exec_scope)) {
472 write_barriers |= dst_access_scope;
473 write_dependency_chain |= dst_exec_scope;
John Zulauf9cb530d2019-09-30 14:14:10 -0600474 }
475}
476
477void SyncValidator::ResetCommandBuffer(VkCommandBuffer command_buffer) {
478 auto *tracker = GetAccessTrackerNoInsert(command_buffer);
479 if (tracker) {
480 tracker->Reset();
481 }
482}
483
John Zulauf5c5e88d2019-12-26 11:22:02 -0700484void SyncValidator::ApplyGlobalBarriers(ResourceAccessTracker *tracker, VkPipelineStageFlags srcStageMask,
John Zulauf36bcf6a2020-02-03 15:12:52 -0700485 VkPipelineStageFlags dstStageMask, SyncStageAccessFlags src_access_scope,
486 SyncStageAccessFlags dst_access_scope, uint32_t memoryBarrierCount,
John Zulauf9cb530d2019-09-30 14:14:10 -0600487 const VkMemoryBarrier *pMemoryBarriers) {
488 // TODO: Implement this better (maybe some delayed/on-demand integration).
John Zulauf36bcf6a2020-02-03 15:12:52 -0700489 ApplyGlobalBarrierFunctor barriers_functor(srcStageMask, dstStageMask, src_access_scope, dst_access_scope, memoryBarrierCount,
John Zulauf9cb530d2019-09-30 14:14:10 -0600490 pMemoryBarriers);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700491 for (auto &mem_access_pair : tracker->GetMemoryAccessMap()) {
John Zulauf9cb530d2019-09-30 14:14:10 -0600492 UpdateMemoryAccessState(&mem_access_pair.second, full_range, barriers_functor);
493 }
John Zulauf5c5e88d2019-12-26 11:22:02 -0700494 for (auto &image_access_pair : tracker->GetImageAccessMap()) {
495 UpdateMemoryAccessState(&image_access_pair.second, full_range, barriers_functor);
496 }
John Zulauf9cb530d2019-09-30 14:14:10 -0600497}
498
John Zulauf36bcf6a2020-02-03 15:12:52 -0700499void SyncValidator::ApplyBufferBarriers(ResourceAccessTracker *tracker, VkPipelineStageFlags src_exec_scope,
500 SyncStageAccessFlags src_stage_accesses, VkPipelineStageFlags dst_exec_scope,
501 SyncStageAccessFlags dst_stage_accesses, uint32_t barrier_count,
John Zulauf9cb530d2019-09-30 14:14:10 -0600502 const VkBufferMemoryBarrier *barriers) {
503 // TODO Implement this at subresource/memory_range accuracy
504 for (uint32_t index = 0; index < barrier_count; index++) {
505 const auto &barrier = barriers[index];
506 const auto *buffer = Get<BUFFER_STATE>(barrier.buffer);
507 if (!buffer) continue;
John Zulauf5c5e88d2019-12-26 11:22:02 -0700508 auto *accesses = tracker->GetMemoryAccessesNoInsert(buffer->binding.mem_state->mem);
John Zulauf9cb530d2019-09-30 14:14:10 -0600509 if (!accesses) continue;
John Zulauf5c5e88d2019-12-26 11:22:02 -0700510 ResourceAccessRange range = MakeMemoryAccessRange(*buffer, barrier.offset, barrier.size);
John Zulauf9cb530d2019-09-30 14:14:10 -0600511 UpdateMemoryAccessState(
512 accesses, range,
John Zulauf36bcf6a2020-02-03 15:12:52 -0700513 ApplyMemoryAccessBarrierFunctor(src_exec_scope, AccessScope(src_stage_accesses, barrier.srcAccessMask), dst_exec_scope,
514 AccessScope(dst_stage_accesses, barrier.dstAccessMask)));
John Zulauf9cb530d2019-09-30 14:14:10 -0600515 }
516}
517
John Zulauf36bcf6a2020-02-03 15:12:52 -0700518void SyncValidator::ApplyImageBarriers(ResourceAccessTracker *tracker, VkPipelineStageFlags src_exec_scope,
519 SyncStageAccessFlags src_stage_accesses, VkPipelineStageFlags dst_exec_scope,
520 SyncStageAccessFlags dst_stage_accesses, uint32_t barrier_count,
John Zulauf5c5e88d2019-12-26 11:22:02 -0700521 const VkImageMemoryBarrier *barriers) {
522 for (uint32_t index = 0; index < barrier_count; index++) {
523 const auto &barrier = barriers[index];
524 const auto *image = Get<IMAGE_STATE>(barrier.image);
525 if (!image) continue;
526 auto *accesses = tracker->GetImageAccessesNoInsert(image->image);
527 if (!accesses) continue;
528 auto subresource_range = NormalizeSubresourceRange(image->createInfo, barrier.subresourceRange);
529 subresource_adapter::RangeGenerator range_gen(image->range_encoder, subresource_range);
John Zulauf36bcf6a2020-02-03 15:12:52 -0700530 const ApplyMemoryAccessBarrierFunctor barrier_action(src_exec_scope, AccessScope(src_stage_accesses, barrier.srcAccessMask),
531 dst_exec_scope,
532 AccessScope(dst_stage_accesses, barrier.dstAccessMask));
John Zulauf5c5e88d2019-12-26 11:22:02 -0700533 for (; range_gen->non_empty(); ++range_gen) {
534 UpdateMemoryAccessState(accesses, *range_gen, barrier_action);
535 }
John Zulauf9cb530d2019-09-30 14:14:10 -0600536 }
John Zulauf9cb530d2019-09-30 14:14:10 -0600537}
538
539bool SyncValidator::PreCallValidateCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
540 uint32_t regionCount, const VkBufferCopy *pRegions) const {
541 bool skip = false;
542 const auto *const const_this = this;
543 const auto *tracker = const_this->GetAccessTracker(commandBuffer);
544 if (tracker) {
545 // If we have no previous accesses, we have no hazards
546 // TODO: make this sub-resource capable
547 // TODO: make this general, and stuff it into templates/utility functions
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);
John Zulauf9cb530d2019-09-30 14:14:10 -0600559 auto hazard = DetectHazard(*src_access, SYNC_TRANSFER_TRANSFER_READ, src_range);
560 if (hazard.hazard) {
561 // TODO -- add tag information to log msg when useful.
562 skip |= LogError(srcBuffer, string_SyncHazardVUID(hazard.hazard), "Hazard %s for srcBuffer %s, region %" PRIu32,
563 string_SyncHazard(hazard.hazard), report_data->FormatHandle(srcBuffer).c_str(), region);
564 }
565 }
566 if (dst_access && !skip) {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700567 ResourceAccessRange dst_range = MakeMemoryAccessRange(*dst_buffer, copy_region.dstOffset, copy_region.size);
John Zulauf9cb530d2019-09-30 14:14:10 -0600568 auto hazard = DetectHazard(*dst_access, SYNC_TRANSFER_TRANSFER_WRITE, dst_range);
569 if (hazard.hazard) {
570 skip |= LogError(dstBuffer, string_SyncHazardVUID(hazard.hazard), "Hazard %s for dstBuffer %s, region %" PRIu32,
571 string_SyncHazard(hazard.hazard), report_data->FormatHandle(dstBuffer).c_str(), region);
572 }
573 }
574 if (skip) break;
575 }
576 }
577 return skip;
578}
579
580void SyncValidator::PreCallRecordCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
581 uint32_t regionCount, const VkBufferCopy *pRegions) {
582 auto *tracker = GetAccessTracker(commandBuffer);
583 assert(tracker);
584 const auto *src_buffer = Get<BUFFER_STATE>(srcBuffer);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700585 const auto src_access =
586 (src_buffer && !src_buffer->sparse) ? tracker->GetMemoryAccesses(src_buffer->binding.mem_state->mem) : nullptr;
John Zulauf9cb530d2019-09-30 14:14:10 -0600587 const auto *dst_buffer = Get<BUFFER_STATE>(dstBuffer);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700588 const auto dst_access =
589 (dst_buffer && !dst_buffer->sparse) ? tracker->GetMemoryAccesses(dst_buffer->binding.mem_state->mem) : nullptr;
John Zulauf9cb530d2019-09-30 14:14:10 -0600590
591 for (uint32_t region = 0; region < regionCount; region++) {
592 const auto &copy_region = pRegions[region];
593 if (src_access) {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700594 ResourceAccessRange src_range = MakeMemoryAccessRange(*src_buffer, copy_region.srcOffset, copy_region.size);
595 UpdateAccessState(src_access, SYNC_TRANSFER_TRANSFER_READ, src_range, tag);
John Zulauf9cb530d2019-09-30 14:14:10 -0600596 }
597 if (dst_access) {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700598 ResourceAccessRange dst_range = MakeMemoryAccessRange(*dst_buffer, copy_region.dstOffset, copy_region.size);
599 UpdateAccessState(dst_access, SYNC_TRANSFER_TRANSFER_WRITE, dst_range, tag);
600 }
601 }
602}
603
604bool SyncValidator::PreCallValidateCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
605 VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
606 const VkImageCopy *pRegions) const {
607 bool skip = false;
608 auto *tracker = GetAccessTracker(commandBuffer);
609 if (tracker) {
610 const auto *src_image = Get<IMAGE_STATE>(srcImage);
611 const auto src_access = tracker->GetImageAccesses(srcImage);
612 const auto *dst_image = Get<IMAGE_STATE>(dstImage);
613 const auto dst_access = tracker->GetImageAccesses(dstImage);
614
615 for (uint32_t region = 0; region < regionCount; region++) {
616 const auto &copy_region = pRegions[region];
617 if (src_access) {
618 auto hazard = DetectHazard(*src_image, *src_access, SYNC_TRANSFER_TRANSFER_READ, copy_region.srcSubresource,
619 copy_region.srcOffset, copy_region.extent);
620 if (hazard.hazard) {
621 skip |= LogError(srcImage, string_SyncHazardVUID(hazard.hazard), "Hazard %s for srcImage %s, region %" PRIu32,
622 string_SyncHazard(hazard.hazard), report_data->FormatHandle(srcImage).c_str(), region);
623 }
624 }
625 if (dst_access) {
626 auto hazard = DetectHazard(*dst_image, *dst_access, SYNC_TRANSFER_TRANSFER_WRITE, copy_region.dstSubresource,
627 copy_region.dstOffset, copy_region.extent);
628 if (hazard.hazard) {
629 skip |= LogError(dstImage, string_SyncHazardVUID(hazard.hazard), "Hazard %s for dstImage %s, region %" PRIu32,
630 string_SyncHazard(hazard.hazard), report_data->FormatHandle(dstImage).c_str(), region);
631 }
632 }
633 }
634 }
635 return skip;
636}
637
638void SyncValidator::PreCallRecordCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
639 VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
640 const VkImageCopy *pRegions) {
641 auto *tracker = GetAccessTracker(commandBuffer);
642 assert(tracker);
643 auto *src_image = Get<IMAGE_STATE>(srcImage);
644 auto src_access = tracker->GetImageAccesses(srcImage);
645 auto *dst_image = Get<IMAGE_STATE>(dstImage);
646 auto dst_access = tracker->GetImageAccesses(dstImage);
647
648 for (uint32_t region = 0; region < regionCount; region++) {
649 const auto &copy_region = pRegions[region];
650 if (src_access) {
651 UpdateAccessState(*src_image, src_access, SYNC_TRANSFER_TRANSFER_READ, copy_region.srcSubresource,
652 copy_region.srcOffset, copy_region.extent, tag);
653 }
654 if (dst_access) {
655 UpdateAccessState(*dst_image, dst_access, SYNC_TRANSFER_TRANSFER_WRITE, copy_region.dstSubresource,
656 copy_region.dstOffset, copy_region.extent, tag);
John Zulauf9cb530d2019-09-30 14:14:10 -0600657 }
658 }
659}
660
661bool SyncValidator::PreCallValidateCmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask,
662 VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags,
663 uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
664 uint32_t bufferMemoryBarrierCount,
665 const VkBufferMemoryBarrier *pBufferMemoryBarriers,
666 uint32_t imageMemoryBarrierCount,
667 const VkImageMemoryBarrier *pImageMemoryBarriers) const {
668 bool skip = false;
John Zulauf0cb5be22020-01-23 12:18:22 -0700669 const auto *tracker = GetAccessTracker(commandBuffer);
670 if (!tracker) return skip;
671
672 const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
673 assert(cb_state);
674 if (!cb_state) return skip;
675
676 const auto src_stage_mask = ExpandPipelineStages(GetQueueFlags(*cb_state), srcStageMask);
John Zulauf36bcf6a2020-02-03 15:12:52 -0700677 const auto src_exec_scope = WithEarlierPipelineStages(src_stage_mask);
678 auto src_stage_accesses = AccessScopeByStage(src_stage_mask);
John Zulauf0cb5be22020-01-23 12:18:22 -0700679 // Validate Image Layout transitions
680 for (uint32_t index = 0; index < imageMemoryBarrierCount; index++) {
681 const auto &barrier = pImageMemoryBarriers[index];
682 if (barrier.newLayout == barrier.oldLayout) continue; // Only interested in layout transitions at this point.
683 const auto *image_state = Get<IMAGE_STATE>(barrier.image);
684 if (!image_state) continue;
John Zulauf36bcf6a2020-02-03 15:12:52 -0700685 const auto hazard = DetectImageBarrierHazard(*tracker, *image_state, src_exec_scope, src_stage_accesses, barrier);
John Zulauf0cb5be22020-01-23 12:18:22 -0700686 if (hazard.hazard) {
687 // TODO -- add tag information to log msg when useful.
688 skip |= LogError(barrier.image, string_SyncHazardVUID(hazard.hazard), "Hazard %s for image barrier %" PRIu32 " %s",
689 string_SyncHazard(hazard.hazard), index, report_data->FormatHandle(barrier.image).c_str());
690 }
691 }
John Zulauf9cb530d2019-09-30 14:14:10 -0600692
693 return skip;
694}
695
696void SyncValidator::PreCallRecordCmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask,
697 VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags,
698 uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
699 uint32_t bufferMemoryBarrierCount,
700 const VkBufferMemoryBarrier *pBufferMemoryBarriers,
701 uint32_t imageMemoryBarrierCount,
702 const VkImageMemoryBarrier *pImageMemoryBarriers) {
703 // Just implement the buffer barrier for now
704 auto *tracker = GetAccessTracker(commandBuffer);
705 assert(tracker);
John Zulauf9cb530d2019-09-30 14:14:10 -0600706
John Zulauf0cb5be22020-01-23 12:18:22 -0700707 const auto cb_state = Get<CMD_BUFFER_STATE>(commandBuffer);
708 assert(cb_state);
709 if (!cb_state) return;
710
711 const auto src_stage_mask = ExpandPipelineStages(GetQueueFlags(*cb_state), srcStageMask);
John Zulauf36bcf6a2020-02-03 15:12:52 -0700712 auto src_stage_accesses = AccessScopeByStage(src_stage_mask);
John Zulauf0cb5be22020-01-23 12:18:22 -0700713 const auto dst_stage_mask = ExpandPipelineStages(GetQueueFlags(*cb_state), dstStageMask);
John Zulauf36bcf6a2020-02-03 15:12:52 -0700714 auto dst_stage_accesses = AccessScopeByStage(dst_stage_mask);
715 const auto src_exec_scope = WithEarlierPipelineStages(src_stage_mask);
716 const auto dst_exec_scope = WithLaterPipelineStages(dst_stage_mask);
717 ApplyBufferBarriers(tracker, src_exec_scope, src_stage_accesses, dst_exec_scope, dst_stage_accesses, bufferMemoryBarrierCount,
John Zulauf9cb530d2019-09-30 14:14:10 -0600718 pBufferMemoryBarriers);
John Zulauf36bcf6a2020-02-03 15:12:52 -0700719 ApplyImageBarriers(tracker, src_exec_scope, src_stage_accesses, dst_exec_scope, dst_stage_accesses, imageMemoryBarrierCount,
John Zulauf5c5e88d2019-12-26 11:22:02 -0700720 pImageMemoryBarriers);
John Zulauf9cb530d2019-09-30 14:14:10 -0600721
722 // 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 -0700723 ApplyGlobalBarriers(tracker, src_exec_scope, dst_exec_scope, src_stage_accesses, dst_stage_accesses, memoryBarrierCount,
John Zulauf0cb5be22020-01-23 12:18:22 -0700724 pMemoryBarriers);
John Zulauf9cb530d2019-09-30 14:14:10 -0600725}
726
727void SyncValidator::PostCallRecordCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo,
728 const VkAllocationCallbacks *pAllocator, VkDevice *pDevice, VkResult result) {
729 // The state tracker sets up the device state
730 StateTracker::PostCallRecordCreateDevice(gpu, pCreateInfo, pAllocator, pDevice, result);
731
732 // Add the callback hooks for the functions that are either broadly or deeply used and that the ValidationStateTracker refactor
733 // would be messier without.
734 // TODO: Find a good way to do this hooklessly.
735 ValidationObject *device_object = GetLayerDataPtr(get_dispatch_key(*pDevice), layer_data_map);
736 ValidationObject *validation_data = GetValidationObject(device_object->object_dispatch, LayerObjectTypeSyncValidation);
737 SyncValidator *sync_device_state = static_cast<SyncValidator *>(validation_data);
738
739 sync_device_state->SetCommandBufferResetCallback(
740 [sync_device_state](VkCommandBuffer command_buffer) -> void { sync_device_state->ResetCommandBuffer(command_buffer); });
741}