blob: 1f36907ec9127e268dcd7f2e38e076ba9899fba4 [file] [log] [blame]
John Zulauf9cb530d2019-09-30 14:14:10 -06001/* Copyright (c) 2019 The Khronos Group Inc.
2 * Copyright (c) 2019 Valve Corporation
3 * Copyright (c) 2019 LunarG, Inc.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 * Author: John Zulauf <jzulauf@lunarg.com>
18 */
19
20#include <limits>
21#include <vector>
22#include "synchronization_validation.h"
23
24static const char *string_SyncHazardVUID(SyncHazard hazard) {
25 switch (hazard) {
26 case SyncHazard::NONE:
John Zulauf2f952d22020-02-10 11:34:51 -070027 return "SYNC-HAZARD-NONE";
John Zulauf9cb530d2019-09-30 14:14:10 -060028 break;
29 case SyncHazard::READ_AFTER_WRITE:
30 return "SYNC-HAZARD-READ_AFTER_WRITE";
31 break;
32 case SyncHazard::WRITE_AFTER_READ:
33 return "SYNC-HAZARD-WRITE_AFTER_READ";
34 break;
35 case SyncHazard::WRITE_AFTER_WRITE:
36 return "SYNC-HAZARD-WRITE_AFTER_WRITE";
37 break;
John Zulauf2f952d22020-02-10 11:34:51 -070038 case SyncHazard::READ_RACING_WRITE:
39 return "SYNC-HAZARD-READ-RACING-WRITE";
40 break;
41 case SyncHazard::WRITE_RACING_WRITE:
42 return "SYNC-HAZARD-WRITE-RACING-WRITE";
43 break;
44 case SyncHazard::WRITE_RACING_READ:
45 return "SYNC-HAZARD-WRITE-RACING-READ";
46 break;
John Zulauf9cb530d2019-09-30 14:14:10 -060047 default:
48 assert(0);
49 }
50 return "SYNC-HAZARD-INVALID";
51}
52
53static const char *string_SyncHazard(SyncHazard hazard) {
54 switch (hazard) {
55 case SyncHazard::NONE:
56 return "NONR";
57 break;
58 case SyncHazard::READ_AFTER_WRITE:
59 return "READ_AFTER_WRITE";
60 break;
61 case SyncHazard::WRITE_AFTER_READ:
62 return "WRITE_AFTER_READ";
63 break;
64 case SyncHazard::WRITE_AFTER_WRITE:
65 return "WRITE_AFTER_WRITE";
66 break;
John Zulauf2f952d22020-02-10 11:34:51 -070067 case SyncHazard::READ_RACING_WRITE:
68 return "READ_RACING_WRITE";
69 break;
70 case SyncHazard::WRITE_RACING_WRITE:
71 return "WRITE_RACING_WRITE";
72 break;
73 case SyncHazard::WRITE_RACING_READ:
74 return "WRITE_RACING_READ";
75 break;
John Zulauf9cb530d2019-09-30 14:14:10 -060076 default:
77 assert(0);
78 }
79 return "INVALID HAZARD";
80}
81
John Zulauf0cb5be22020-01-23 12:18:22 -070082// Expand the pipeline stage without regard to whether the are valid w.r.t. queue or extension
83VkPipelineStageFlags ExpandPipelineStages(VkQueueFlags queue_flags, VkPipelineStageFlags stage_mask) {
84 VkPipelineStageFlags expanded = stage_mask;
85 if (VK_PIPELINE_STAGE_ALL_COMMANDS_BIT & stage_mask) {
86 expanded = expanded & ~VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
87 for (const auto &all_commands : syncAllCommandStagesByQueueFlags) {
88 if (all_commands.first & queue_flags) {
89 expanded |= all_commands.second;
90 }
91 }
92 }
93 if (VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT & stage_mask) {
94 expanded = expanded & ~VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
95 expanded |= syncAllCommandStagesByQueueFlags.at(VK_QUEUE_GRAPHICS_BIT) & ~VK_PIPELINE_STAGE_HOST_BIT;
96 }
97 return expanded;
98}
99
John Zulauf36bcf6a2020-02-03 15:12:52 -0700100VkPipelineStageFlags RelatedPipelineStages(VkPipelineStageFlags stage_mask,
101 std::map<VkPipelineStageFlagBits, VkPipelineStageFlags> &map) {
102 VkPipelineStageFlags unscanned = stage_mask;
103 VkPipelineStageFlags related = 0;
104 for (const auto entry : map) {
105 const auto stage = entry.first;
106 if (stage & unscanned) {
107 related = related | entry.second;
108 unscanned = unscanned & ~stage;
109 if (!unscanned) break;
110 }
111 }
112 return related;
113}
114
115VkPipelineStageFlags WithEarlierPipelineStages(VkPipelineStageFlags stage_mask) {
116 return stage_mask | RelatedPipelineStages(stage_mask, syncLogicallyEarlierStages);
117}
118
119VkPipelineStageFlags WithLaterPipelineStages(VkPipelineStageFlags stage_mask) {
120 return stage_mask | RelatedPipelineStages(stage_mask, syncLogicallyLaterStages);
121}
122
John Zulauf5c5e88d2019-12-26 11:22:02 -0700123static const ResourceAccessRange full_range(std::numeric_limits<VkDeviceSize>::min(), std::numeric_limits<VkDeviceSize>::max());
124static ResourceAccessRange MakeMemoryAccessRange(const BUFFER_STATE &buffer, VkDeviceSize offset, VkDeviceSize size) {
John Zulauf9cb530d2019-09-30 14:14:10 -0600125 assert(!buffer.sparse);
126 const auto base = offset + buffer.binding.offset;
John Zulauf5c5e88d2019-12-26 11:22:02 -0700127 return ResourceAccessRange(base, base + size);
128}
129
John Zulauf3d84f1b2020-03-09 13:33:25 -0600130AccessTrackerContext::AccessTrackerContext(uint32_t subpass, VkQueueFlags queue_flags,
131 const std::vector<SubpassDependencyGraphNode> &dependencies,
132 const std::vector<AccessTrackerContext> &contexts,
133 AccessTrackerContext *external_context) {
134 Reset();
135 const auto &subpass_dep = dependencies[subpass];
136 prev_.reserve(subpass_dep.prev.size());
137 for (const auto &prev_dep : subpass_dep.prev) {
138 assert(prev_dep.dependency);
139 const auto dep = *prev_dep.dependency;
140 prev_.emplace_back(const_cast<AccessTrackerContext *>(&contexts[dep.srcSubpass]), queue_flags, dep);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700141 }
John Zulauf3d84f1b2020-03-09 13:33:25 -0600142
143 async_.reserve(subpass_dep.async.size());
144 for (const auto async_subpass : subpass_dep.async) {
145 async_.emplace_back(const_cast<AccessTrackerContext *>(&contexts[async_subpass]));
146 }
147 if (subpass_dep.barrier_from_external)
148 external_ = TrackBack(external_context, queue_flags, *subpass_dep.barrier_from_external);
149 else {
150 external_ = TrackBack();
151 }
John Zulauf5c5e88d2019-12-26 11:22:02 -0700152}
153
John Zulauf3d84f1b2020-03-09 13:33:25 -0600154// A recursive range walker for hazard detection, first for the current context and the (DetectHazardRecur) to walk
155// the DAG of the contexts (for example subpasses)
156template <typename Detector>
157HazardResult AccessTrackerContext::DetectHazard(const VulkanTypedHandle &handle, const Detector &detector,
158 const ResourceAccessRange &range, SyncBarrierStack *barrier_stack) const {
159 const auto access_tracker = GetAccessTracker(handle);
160 bool whole_range_gap = true;
161 HazardResult hazard;
162 if (access_tracker) {
163 const auto &accesses = access_tracker->GetCurrentAccessMap();
164 const auto from = accesses.lower_bound(range);
165 if (from != accesses.end() && from->first.intersects(range)) {
166 whole_range_gap = false;
167 const auto to = accesses.upper_bound(range);
168 ResourceAccessRange gap = {range.begin, range.begin};
169 for (auto pos = from; pos != to; ++pos) {
170 hazard = detector.Detect(pos, barrier_stack);
171 if (hazard.hazard) return hazard;
172
173 // Check for short circuiting recursion over pos->first
174 // If we've just checked against a write we don't have to looke any further...
175 // however even if the current usage is write and there is not hazard with a stored read, we still have to
176 // recur to ensure it's safe against *all* prior/parallel accesses.
177 auto upper_bound = std::min(range.end, pos->first.end);
178 if (detector.ShortCircuit(pos, barrier_stack)) {
179 gap.end = pos->first.begin;
180 } else {
181 // make sure we don't go past range
182 gap.end = upper_bound;
183 }
184 if (!gap.empty()) {
185 // Must recur on all gaps
186 hazard = DetectHazardRecur(handle, detector, gap, barrier_stack);
187 if (hazard.hazard) return hazard;
188 }
189 gap.begin = upper_bound;
190 }
191 }
192 }
193
194 if (whole_range_gap) { // There's no accesses recorded for this range for this context and resource
195 hazard = DetectHazardRecur(handle, detector, range, barrier_stack);
196 }
197 // We only check the async list for top level contexts (empty stack)
198 // Async check are not done at recursive levels, as the async lists are exhaustive for the top-level context
199 if (barrier_stack->size() == 0) {
200 for (const auto &async_context : async_) {
201 hazard = async_context->DetectAsyncHazard(handle, detector, range);
202 if (hazard.hazard) return hazard;
203 }
204 }
205
206 return hazard;
207}
208
209// A non recursive range walker for the asynchronous contexts (those we have no barriers with)
210template <typename Detector>
211HazardResult AccessTrackerContext::DetectAsyncHazard(const VulkanTypedHandle &handle, const Detector &detector,
212 const ResourceAccessRange &range) const {
213 const auto access_tracker = GetAccessTracker(handle);
214 HazardResult hazard;
215 if (access_tracker) {
216 auto accesses = access_tracker->GetCurrentAccessMap();
217 const auto from = accesses.lower_bound(range);
218 const auto to = accesses.upper_bound(range);
219 for (auto pos = from; pos != to; ++pos) {
220 hazard = detector.DetectAsync(pos);
221 if (hazard.hazard) break;
222 }
223 }
224 return hazard;
225}
226
227// Walk the contents or the context's predecessors, checking for hazards invoking the recursive and non-recursive range walkers
228// as appropriate for the type of predecessor
229template <typename Detector>
230HazardResult AccessTrackerContext::DetectHazardRecur(const VulkanTypedHandle &handle, const Detector &detector,
231 const ResourceAccessRange &range, SyncBarrierStack *barrier_stack) const {
232 HazardResult hazard;
233
234 assert(barrier_stack); // Barrier stack is a pointer only by convention (non-const objects to be passed by pointer)
235 for (const auto &prev_dep : prev_) {
236 barrier_stack->push_back(&prev_dep.barrier);
237 hazard = prev_dep.context->DetectHazard(handle, detector, range, barrier_stack);
238 barrier_stack->pop_back();
239 if (hazard.hazard) return hazard;
240 }
241 if (external_.context) {
242 barrier_stack->push_back(&external_.barrier);
243 hazard = external_.context->DetectHazard(handle, detector, range, barrier_stack);
244 barrier_stack->pop_back();
245 if (hazard.hazard) return hazard;
246 }
247
248 return hazard;
249}
250
251template <typename Detector>
252HazardResult AccessTrackerContext::DetectHazard(const VulkanTypedHandle &handle, const Detector &detector,
253 const ResourceAccessRange &range) const {
254 SyncBarrierStack barrier_stack;
255 return DetectHazard(handle, detector, range, &barrier_stack);
256}
257
258class HazardDetector {
259 SyncStageAccessIndex usage_index_;
260
261 public:
262 HazardResult Detect(const ResourceAccessRangeMap::const_iterator &pos, SyncBarrierStack *barrier_stack) const {
263 return pos->second.DetectHazard(usage_index_, barrier_stack);
264 }
265 bool ShortCircuit(const ResourceAccessRangeMap::const_iterator &pos, SyncBarrierStack *barrier_stack) const {
266 // Check for short circuiting recursion over pos->first
267 // If we've just checked against a write we don't have to looke any further...
268 // however even if the current usage is write and there is not hazard with a stored read, we still have to
269 // recur to ensure it's safe against *all* prior/parallel accesses.
270 return pos->second.HasWriteOp();
271 }
272 HazardResult DetectAsync(const ResourceAccessRangeMap::const_iterator &pos) const {
273 return pos->second.DetectAsyncHazard(usage_index_);
274 }
275 HazardDetector(SyncStageAccessIndex usage) : usage_index_(usage) {}
276};
277
278HazardResult AccessTrackerContext::DetectHazard(const VulkanTypedHandle &handle, SyncStageAccessIndex usage_index,
279 const ResourceAccessRange &range) const {
280 HazardDetector detector(usage_index);
281 return DetectHazard(handle, detector, range);
282}
283
284void CommandBufferAccessContext::BeginRenderPass(const RENDER_PASS_STATE &rp_state) {
285 // Create an access context for the first subpass and add it to the command buffers collection
286 render_pass_contexts_.emplace_back(queue_flags_, &rp_state.subpass_dependencies, &cb_tracker_context_);
287 current_renderpass_context_ = &render_pass_contexts_.back();
288 current_context_ = &current_renderpass_context_->CurrentContext();
289}
290
291void CommandBufferAccessContext::NextRenderPass(const RENDER_PASS_STATE &rp_state) {
292 assert(current_renderpass_context_);
293 current_renderpass_context_->NextSubpass(queue_flags_, &cb_tracker_context_);
294 current_context_ = &current_renderpass_context_->CurrentContext();
295}
296
297HazardResult AccessTrackerContext::DetectHazard(const IMAGE_STATE &image, SyncStageAccessIndex current_usage,
298 const VkImageSubresourceLayers &subresource, const VkOffset3D &offset,
299 const VkExtent3D &extent) const {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700300 // TODO: replace the encoder/generator with offset3D/extent3D aware versions
301 VkImageSubresourceRange subresource_range = {subresource.aspectMask, subresource.mipLevel, 1, subresource.baseArrayLayer,
302 subresource.layerCount};
locke-lunarg1dbbb9e2020-02-28 22:43:53 -0700303 VkExtent3D subresource_extent = GetImageSubresourceExtent(&image, &subresource);
304 subresource_adapter::OffsetRangeEncoder encoder(image.full_range, subresource_extent);
305 subresource_adapter::OffsetRangeGenerator range_gen(encoder, subresource_range, offset, extent);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600306 VulkanTypedHandle image_handle(image.image, kVulkanObjectTypeImage);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700307 for (; range_gen->non_empty(); ++range_gen) {
John Zulauf3d84f1b2020-03-09 13:33:25 -0600308 HazardResult hazard = DetectHazard(image_handle, current_usage, *range_gen);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700309 if (hazard.hazard) return hazard;
310 }
311 return HazardResult();
John Zulauf9cb530d2019-09-30 14:14:10 -0600312}
313
John Zulauf3d84f1b2020-03-09 13:33:25 -0600314class BarrierHazardDetector {
315 public:
316 BarrierHazardDetector(SyncStageAccessIndex usage_index, VkPipelineStageFlags src_exec_scope,
317 SyncStageAccessFlags src_access_scope)
318 : usage_index_(usage_index), src_exec_scope_(src_exec_scope), src_access_scope_(src_access_scope) {}
319
320 HazardResult Detect(const ResourceAccessRangeMap::const_iterator &pos, SyncBarrierStack *barrier_stack) const {
321 return pos->second.DetectBarrierHazard(usage_index_, src_exec_scope_, src_access_scope_, barrier_stack);
John Zulauf0cb5be22020-01-23 12:18:22 -0700322 }
John Zulauf3d84f1b2020-03-09 13:33:25 -0600323 bool ShortCircuit(const ResourceAccessRangeMap::const_iterator &pos, SyncBarrierStack *barrier_stack) const { return false; }
324 HazardResult DetectAsync(const ResourceAccessRangeMap::const_iterator &pos) const {
325 // Async barrier hazard detection can use the same path as the usage index is not IsRead, but is IsWrite
326 return pos->second.DetectAsyncHazard(usage_index_);
327 }
328
329 private:
330 SyncStageAccessIndex usage_index_;
331 VkPipelineStageFlags src_exec_scope_;
332 SyncStageAccessFlags src_access_scope_;
333};
334
335HazardResult AccessTrackerContext::DetectBarrierHazard(const VulkanTypedHandle &handle, SyncStageAccessIndex current_usage,
336 VkPipelineStageFlags src_exec_scope, SyncStageAccessFlags src_access_scope,
337 const ResourceAccessRange &range) const {
338 BarrierHazardDetector detector(current_usage, src_exec_scope, src_access_scope);
339 return DetectHazard(handle, detector, range);
John Zulauf0cb5be22020-01-23 12:18:22 -0700340}
341
John Zulauf3d84f1b2020-03-09 13:33:25 -0600342HazardResult DetectImageBarrierHazard(const AccessTrackerContext &context, const IMAGE_STATE &image,
John Zulauf36bcf6a2020-02-03 15:12:52 -0700343 VkPipelineStageFlags src_exec_scope, SyncStageAccessFlags src_stage_accesses,
John Zulauf0cb5be22020-01-23 12:18:22 -0700344 const VkImageMemoryBarrier &barrier) {
John Zulauf0cb5be22020-01-23 12:18:22 -0700345 auto subresource_range = NormalizeSubresourceRange(image.createInfo, barrier.subresourceRange);
locke-lunarg1dbbb9e2020-02-28 22:43:53 -0700346 VkImageSubresourceLayers subresource_layers = {subresource_range.aspectMask, 0, subresource_range.baseArrayLayer,
347 subresource_range.layerCount};
John Zulauf3d84f1b2020-03-09 13:33:25 -0600348 const VulkanTypedHandle image_handle(image.image, kVulkanObjectTypeImage);
John Zulauf36bcf6a2020-02-03 15:12:52 -0700349 const auto src_access_scope = SyncStageAccess::AccessScope(src_stage_accesses, barrier.srcAccessMask);
locke-lunarg1dbbb9e2020-02-28 22:43:53 -0700350 for (uint32_t mip_index = subresource_range.baseMipLevel; mip_index < subresource_range.levelCount; mip_index++) {
351 subresource_layers.mipLevel = mip_index;
352 VkExtent3D subresource_extent = GetImageSubresourceExtent(&image, &subresource_layers);
353 subresource_adapter::OffsetRangeEncoder encoder(image.full_range, subresource_extent);
354 subresource_adapter::OffsetRangeGenerator range_gen(encoder, subresource_range, {0, 0}, subresource_extent);
355 for (; range_gen->non_empty(); ++range_gen) {
356 HazardResult hazard = context.DetectBarrierHazard(image_handle, SyncStageAccessIndex::SYNC_IMAGE_LAYOUT_TRANSITION,
357 src_exec_scope, src_access_scope, *range_gen);
358 if (hazard.hazard) return hazard;
359 }
John Zulauf0cb5be22020-01-23 12:18:22 -0700360 }
361 return HazardResult();
362}
363
John Zulauf9cb530d2019-09-30 14:14:10 -0600364template <typename Flags, typename Map>
365SyncStageAccessFlags AccessScopeImpl(Flags flag_mask, const Map &map) {
366 SyncStageAccessFlags scope = 0;
367 for (const auto &bit_scope : map) {
368 if (flag_mask < bit_scope.first) break;
369
370 if (flag_mask & bit_scope.first) {
371 scope |= bit_scope.second;
372 }
373 }
374 return scope;
375}
376
377SyncStageAccessFlags SyncStageAccess::AccessScopeByStage(VkPipelineStageFlags stages) {
378 return AccessScopeImpl(stages, syncStageAccessMaskByStageBit);
379}
380
381SyncStageAccessFlags SyncStageAccess::AccessScopeByAccess(VkAccessFlags accesses) {
382 return AccessScopeImpl(accesses, syncStageAccessMaskByAccessBit);
383}
384
385// Getting from stage mask and access mask to stage/acess masks is something we need to be good at...
386SyncStageAccessFlags SyncStageAccess::AccessScope(VkPipelineStageFlags stages, VkAccessFlags accesses) {
387 // The access scope is the intersection of all stage/access types possible for the enabled stages and the enables accesses
388 // (after doing a couple factoring of common terms the union of stage/access intersections is the intersections of the
389 // union of all stage/access types for all the stages and the same unions for the access mask...
390 return AccessScopeByStage(stages) & AccessScopeByAccess(accesses);
391}
392
393template <typename Action>
John Zulauf5c5e88d2019-12-26 11:22:02 -0700394void UpdateMemoryAccessState(ResourceAccessRangeMap *accesses, const ResourceAccessRange &range, const Action &action) {
John Zulauf9cb530d2019-09-30 14:14:10 -0600395 // TODO -- region/mem-range accuracte update
396 auto pos = accesses->lower_bound(range);
397 if (pos == accesses->end() || !pos->first.intersects(range)) {
398 // The range is empty, fill it with a default value.
399 pos = action.Infill(accesses, pos, range);
400 } else if (range.begin < pos->first.begin) {
401 // Leading empty space, infill
John Zulauf5c5e88d2019-12-26 11:22:02 -0700402 pos = action.Infill(accesses, pos, ResourceAccessRange(range.begin, pos->first.begin));
John Zulauf9cb530d2019-09-30 14:14:10 -0600403 } else if (pos->first.begin < range.begin) {
404 // Trim the beginning if needed
405 pos = accesses->split(pos, range.begin, sparse_container::split_op_keep_both());
406 ++pos;
407 }
408
409 const auto the_end = accesses->end();
410 while ((pos != the_end) && pos->first.intersects(range)) {
411 if (pos->first.end > range.end) {
412 pos = accesses->split(pos, range.end, sparse_container::split_op_keep_both());
413 }
414
415 pos = action(accesses, pos);
416 if (pos == the_end) break;
417
418 auto next = pos;
419 ++next;
420 if ((pos->first.end < range.end) && (next != the_end) && !next->first.is_subsequent_to(pos->first)) {
421 // Need to infill if next is disjoint
422 VkDeviceSize limit = (next == the_end) ? range.end : std::min(range.end, next->first.begin);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700423 ResourceAccessRange new_range(pos->first.end, limit);
John Zulauf9cb530d2019-09-30 14:14:10 -0600424 next = action.Infill(accesses, next, new_range);
425 }
426 pos = next;
427 }
428}
429
430struct UpdateMemoryAccessStateFunctor {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700431 using Iterator = ResourceAccessRangeMap::iterator;
432 Iterator Infill(ResourceAccessRangeMap *accesses, Iterator pos, ResourceAccessRange range) const {
John Zulauf9cb530d2019-09-30 14:14:10 -0600433 return accesses->insert(pos, std::make_pair(range, ResourceAccessState()));
434 }
John Zulauf5c5e88d2019-12-26 11:22:02 -0700435 Iterator operator()(ResourceAccessRangeMap *accesses, Iterator pos) const {
John Zulauf9cb530d2019-09-30 14:14:10 -0600436 auto &access_state = pos->second;
437 access_state.Update(usage, tag);
438 return pos;
439 }
440
441 UpdateMemoryAccessStateFunctor(SyncStageAccessIndex usage_, const ResourceUsageTag &tag_) : usage(usage_), tag(tag_) {}
442 SyncStageAccessIndex usage;
443 const ResourceUsageTag &tag;
444};
445
446struct ApplyMemoryAccessBarrierFunctor {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700447 using Iterator = ResourceAccessRangeMap::iterator;
448 inline Iterator Infill(ResourceAccessRangeMap *accesses, Iterator pos, ResourceAccessRange range) const { return pos; }
John Zulauf9cb530d2019-09-30 14:14:10 -0600449
John Zulauf5c5e88d2019-12-26 11:22:02 -0700450 Iterator operator()(ResourceAccessRangeMap *accesses, Iterator pos) const {
John Zulauf9cb530d2019-09-30 14:14:10 -0600451 auto &access_state = pos->second;
John Zulauf36bcf6a2020-02-03 15:12:52 -0700452 access_state.ApplyMemoryAccessBarrier(src_exec_scope, src_access_scope, dst_exec_scope, dst_access_scope);
John Zulauf9cb530d2019-09-30 14:14:10 -0600453 return pos;
454 }
455
John Zulauf36bcf6a2020-02-03 15:12:52 -0700456 ApplyMemoryAccessBarrierFunctor(VkPipelineStageFlags src_exec_scope_, SyncStageAccessFlags src_access_scope_,
457 VkPipelineStageFlags dst_exec_scope_, SyncStageAccessFlags dst_access_scope_)
458 : src_exec_scope(src_exec_scope_),
459 src_access_scope(src_access_scope_),
460 dst_exec_scope(dst_exec_scope_),
461 dst_access_scope(dst_access_scope_) {}
John Zulauf9cb530d2019-09-30 14:14:10 -0600462
John Zulauf36bcf6a2020-02-03 15:12:52 -0700463 VkPipelineStageFlags src_exec_scope;
464 SyncStageAccessFlags src_access_scope;
465 VkPipelineStageFlags dst_exec_scope;
466 SyncStageAccessFlags dst_access_scope;
John Zulauf9cb530d2019-09-30 14:14:10 -0600467};
468
469struct ApplyGlobalBarrierFunctor {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700470 using Iterator = ResourceAccessRangeMap::iterator;
471 inline Iterator Infill(ResourceAccessRangeMap *accesses, Iterator pos, ResourceAccessRange range) const { return pos; }
John Zulauf9cb530d2019-09-30 14:14:10 -0600472
John Zulauf5c5e88d2019-12-26 11:22:02 -0700473 Iterator operator()(ResourceAccessRangeMap *accesses, Iterator pos) const {
John Zulauf9cb530d2019-09-30 14:14:10 -0600474 auto &access_state = pos->second;
John Zulauf36bcf6a2020-02-03 15:12:52 -0700475 access_state.ApplyExecutionBarrier(src_exec_scope, dst_exec_scope);
John Zulauf9cb530d2019-09-30 14:14:10 -0600476
477 for (const auto &functor : barrier_functor) {
478 functor(accesses, pos);
479 }
480 return pos;
481 }
482
John Zulauf36bcf6a2020-02-03 15:12:52 -0700483 ApplyGlobalBarrierFunctor(VkPipelineStageFlags src_exec_scope, VkPipelineStageFlags dst_exec_scope,
484 SyncStageAccessFlags src_stage_accesses, SyncStageAccessFlags dst_stage_accesses,
John Zulauf9cb530d2019-09-30 14:14:10 -0600485 uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers)
John Zulauf36bcf6a2020-02-03 15:12:52 -0700486 : src_exec_scope(src_exec_scope), dst_exec_scope(dst_exec_scope) {
John Zulauf9cb530d2019-09-30 14:14:10 -0600487 // Don't want to create this per tracked item, but don't want to loop through all tracked items per barrier...
488 barrier_functor.reserve(memoryBarrierCount);
489 for (uint32_t barrier_index = 0; barrier_index < memoryBarrierCount; barrier_index++) {
490 const auto &barrier = pMemoryBarriers[barrier_index];
John Zulauf36bcf6a2020-02-03 15:12:52 -0700491 barrier_functor.emplace_back(src_exec_scope, SyncStageAccess::AccessScope(src_stage_accesses, barrier.srcAccessMask),
492 dst_exec_scope, SyncStageAccess::AccessScope(dst_stage_accesses, barrier.dstAccessMask));
John Zulauf9cb530d2019-09-30 14:14:10 -0600493 }
494 }
495
John Zulauf36bcf6a2020-02-03 15:12:52 -0700496 const VkPipelineStageFlags src_exec_scope;
497 const VkPipelineStageFlags dst_exec_scope;
John Zulauf9cb530d2019-09-30 14:14:10 -0600498 std::vector<ApplyMemoryAccessBarrierFunctor> barrier_functor;
499};
500
John Zulauf3d84f1b2020-03-09 13:33:25 -0600501void AccessTracker::UpdateAccessState(SyncStageAccessIndex current_usage, const ResourceAccessRange &range,
502 const ResourceUsageTag &tag) {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700503 UpdateMemoryAccessStateFunctor action(current_usage, tag);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600504 UpdateMemoryAccessState(&accesses_, range, action);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700505}
506
John Zulauf3d84f1b2020-03-09 13:33:25 -0600507void AccessTrackerContext::UpdateAccessState(const VulkanTypedHandle &handle, SyncStageAccessIndex current_usage,
508 const ResourceAccessRange &range, const ResourceUsageTag &tag) {
509 auto *tracker = GetAccessTracker(handle);
510 assert(tracker);
511 tracker->UpdateAccessState(current_usage, range, tag);
512}
513
514void AccessTracker::UpdateAccessState(const IMAGE_STATE &image, SyncStageAccessIndex current_usage,
515 const VkImageSubresourceLayers &subresource, const VkOffset3D &offset,
516 const VkExtent3D &extent, const ResourceUsageTag &tag) {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700517 // TODO: replace the encoder/generator with offset3D aware versions
518 VkImageSubresourceRange subresource_range = {subresource.aspectMask, subresource.mipLevel, 1, subresource.baseArrayLayer,
519 subresource.layerCount};
locke-lunarg1dbbb9e2020-02-28 22:43:53 -0700520 VkExtent3D subresource_extent = GetImageSubresourceExtent(&image, &subresource);
521 subresource_adapter::OffsetRangeEncoder encoder(image.full_range, subresource_extent);
522 subresource_adapter::OffsetRangeGenerator range_gen(encoder, subresource_range, offset, extent);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700523 for (; range_gen->non_empty(); ++range_gen) {
John Zulauf3d84f1b2020-03-09 13:33:25 -0600524 UpdateAccessState(current_usage, *range_gen, tag);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700525 }
526}
527
John Zulauf3d84f1b2020-03-09 13:33:25 -0600528void AccessTrackerContext::UpdateAccessState(const IMAGE_STATE &image, SyncStageAccessIndex current_usage,
529 const VkImageSubresourceLayers &subresource, const VkOffset3D &offset,
530 const VkExtent3D &extent, const ResourceUsageTag &tag) {
531 const VulkanTypedHandle handle(image.image, kVulkanObjectTypeImage);
532 auto *tracker = GetAccessTracker(handle);
533 assert(tracker);
534 tracker->UpdateAccessState(image, current_usage, subresource, offset, extent, tag);
535}
536
537SyncBarrier::SyncBarrier(VkQueueFlags queue_flags, const VkSubpassDependency2 &barrier) {
538 const auto src_stage_mask = ExpandPipelineStages(queue_flags, barrier.srcStageMask);
539 src_exec_scope = WithEarlierPipelineStages(src_stage_mask);
540 src_access_scope = SyncStageAccess::AccessScope(src_stage_mask, barrier.srcAccessMask);
541 const auto dst_stage_mask = ExpandPipelineStages(queue_flags, barrier.dstStageMask);
542 dst_exec_scope = WithLaterPipelineStages(dst_stage_mask);
543 dst_access_scope = SyncStageAccess::AccessScope(dst_stage_mask, barrier.dstAccessMask);
544}
545
546void ResourceAccessState::ApplyBarrier(const SyncBarrier &barrier) {
547 ApplyExecutionBarrier(barrier.src_exec_scope, barrier.dst_exec_scope);
548 ApplyMemoryAccessBarrier(barrier.src_exec_scope, barrier.src_access_scope, barrier.dst_exec_scope, barrier.dst_access_scope);
549}
550
551ResourceAccessState ResourceAccessState::ApplyBarrierStack(const ResourceAccessState &that, const SyncBarrierStack &barrier_stack) {
552 ResourceAccessState copy = that;
553 for (auto barrier = barrier_stack.begin(); barrier != barrier_stack.end(); ++barrier) {
554 assert(*barrier);
555 copy.ApplyBarrier(*(*barrier));
556 }
557 return copy;
558}
559
560HazardResult ResourceAccessState::DetectHazard(SyncStageAccessIndex usage_index, SyncBarrierStack *barrier_stack) const {
561 if (barrier_stack) {
562 return ApplyBarrierStack(*this, *barrier_stack).DetectHazard(usage_index);
563 }
564 return DetectHazard(usage_index);
565}
566
John Zulauf9cb530d2019-09-30 14:14:10 -0600567HazardResult ResourceAccessState::DetectHazard(SyncStageAccessIndex usage_index) const {
568 HazardResult hazard;
569 auto usage = FlagBit(usage_index);
570 if (IsRead(usage)) {
571 if (IsWriteHazard(usage)) {
572 hazard.Set(READ_AFTER_WRITE, write_tag);
573 }
574 } else {
575 // Assume write
576 // TODO determine what to do with READ-WRITE usage states if any
577 // Write-After-Write check -- if we have a previous write to test against
578 if (last_write && IsWriteHazard(usage)) {
579 hazard.Set(WRITE_AFTER_WRITE, write_tag);
580 } else {
581 // Only look for casus belli for WAR
582 const auto usage_stage = PipelineStageBit(usage_index);
583 for (uint32_t read_index = 0; read_index < last_read_count; read_index++) {
584 if (IsReadHazard(usage_stage, last_reads[read_index])) {
585 hazard.Set(WRITE_AFTER_READ, last_reads[read_index].tag);
586 break;
587 }
588 }
589 }
590 }
591 return hazard;
592}
593
John Zulauf2f952d22020-02-10 11:34:51 -0700594// Asynchronous Hazards occur between subpasses with no connection through the DAG
John Zulauf3d84f1b2020-03-09 13:33:25 -0600595HazardResult ResourceAccessState::DetectAsyncHazard(SyncStageAccessIndex usage_index) const {
John Zulauf2f952d22020-02-10 11:34:51 -0700596 HazardResult hazard;
597 auto usage = FlagBit(usage_index);
598 if (IsRead(usage)) {
599 if (last_write != 0) {
600 hazard.Set(READ_RACING_WRITE, write_tag);
601 }
602 } else {
603 if (last_write != 0) {
604 hazard.Set(WRITE_RACING_WRITE, write_tag);
605 } else if (last_read_count > 0) {
606 hazard.Set(WRITE_RACING_READ, last_reads[0].tag);
607 }
608 }
609 return hazard;
610}
611
John Zulauf36bcf6a2020-02-03 15:12:52 -0700612HazardResult ResourceAccessState::DetectBarrierHazard(SyncStageAccessIndex usage_index, VkPipelineStageFlags src_exec_scope,
John Zulauf3d84f1b2020-03-09 13:33:25 -0600613 SyncStageAccessFlags src_access_scope,
614 SyncBarrierStack *barrier_stack) const {
615 if (barrier_stack) {
616 return ApplyBarrierStack(*this, *barrier_stack).DetectBarrierHazard(usage_index, src_exec_scope, src_access_scope);
617 }
618 return DetectBarrierHazard(usage_index, src_exec_scope, src_access_scope);
619}
620
621HazardResult ResourceAccessState::DetectBarrierHazard(SyncStageAccessIndex usage_index, VkPipelineStageFlags src_exec_scope,
John Zulauf36bcf6a2020-02-03 15:12:52 -0700622 SyncStageAccessFlags src_access_scope) const {
John Zulauf0cb5be22020-01-23 12:18:22 -0700623 // Only supporting image layout transitions for now
624 assert(usage_index == SyncStageAccessIndex::SYNC_IMAGE_LAYOUT_TRANSITION);
625 HazardResult hazard;
626 if (last_write) {
627 // If the previous write is *not* in the 1st access scope
628 // *AND* the current barrier is not in the dependency chain
629 // *AND* the there is no prior memory barrier for the previous write in the dependency chain
630 // then the barrier access is unsafe (R/W after W)
John Zulauf36bcf6a2020-02-03 15:12:52 -0700631 if (((last_write & src_access_scope) == 0) && ((src_exec_scope & write_dependency_chain) == 0) && (write_barriers == 0)) {
John Zulauf0cb5be22020-01-23 12:18:22 -0700632 // TODO: Do we need a difference hazard name for this?
633 hazard.Set(WRITE_AFTER_WRITE, write_tag);
634 }
635 } else {
636 // Look at the reads
637 for (uint32_t read_index = 0; read_index < last_read_count; read_index++) {
John Zulauf36bcf6a2020-02-03 15:12:52 -0700638 const auto &read_access = last_reads[read_index];
639 // If the read stage is not in the src sync sync
640 // *AND* not execution chained with an existing sync barrier (that's the or)
641 // then the barrier access is unsafe (R/W after R)
642 if ((src_exec_scope & (read_access.stage | read_access.barriers)) == 0) {
643 hazard.Set(WRITE_AFTER_READ, read_access.tag);
John Zulauf0cb5be22020-01-23 12:18:22 -0700644 break;
645 }
646 }
647 }
648 return hazard;
649}
650
John Zulauf9cb530d2019-09-30 14:14:10 -0600651void ResourceAccessState::Update(SyncStageAccessIndex usage_index, const ResourceUsageTag &tag) {
652 // Move this logic in the ResourceStateTracker as methods, thereof (or we'll repeat it for every flavor of resource...
653 const auto usage_bit = FlagBit(usage_index);
654 if (IsRead(usage_index)) {
655 // Mulitple outstanding reads may be of interest and do dependency chains independently
656 // However, for purposes of barrier tracking, only one read per pipeline stage matters
657 const auto usage_stage = PipelineStageBit(usage_index);
658 if (usage_stage & last_read_stages) {
659 for (uint32_t read_index = 0; read_index < last_read_count; read_index++) {
660 ReadState &access = last_reads[read_index];
661 if (access.stage == usage_stage) {
662 access.barriers = 0;
663 access.tag = tag;
664 break;
665 }
666 }
667 } else {
668 // We don't have this stage in the list yet...
669 assert(last_read_count < last_reads.size());
670 ReadState &access = last_reads[last_read_count++];
671 access.stage = usage_stage;
672 access.barriers = 0;
673 access.tag = tag;
674 last_read_stages |= usage_stage;
675 }
676 } else {
677 // Assume write
678 // TODO determine what to do with READ-WRITE operations if any
679 // Clobber last read and both sets of barriers... because all we have is DANGER, DANGER, WILL ROBINSON!!!
680 // if the last_reads/last_write were unsafe, we've reported them,
681 // in either case the prior access is irrelevant, we can overwrite them as *this* write is now after them
682 last_read_count = 0;
683 last_read_stages = 0;
684
685 write_barriers = 0;
686 write_dependency_chain = 0;
687 write_tag = tag;
688 last_write = usage_bit;
689 }
690}
691void ResourceAccessState::ApplyExecutionBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask) {
692 // Execution Barriers only protect read operations
693 for (uint32_t read_index = 0; read_index < last_read_count; read_index++) {
694 ReadState &access = last_reads[read_index];
695 // The | implements the "dependency chain" logic for this access, as the barriers field stores the second sync scope
696 if (srcStageMask & (access.stage | access.barriers)) {
697 access.barriers |= dstStageMask;
698 }
699 }
700 if (write_dependency_chain & srcStageMask) write_dependency_chain |= dstStageMask;
701}
702
John Zulauf36bcf6a2020-02-03 15:12:52 -0700703void ResourceAccessState::ApplyMemoryAccessBarrier(VkPipelineStageFlags src_exec_scope, SyncStageAccessFlags src_access_scope,
704 VkPipelineStageFlags dst_exec_scope, SyncStageAccessFlags dst_access_scope) {
John Zulauf9cb530d2019-09-30 14:14:10 -0600705 // Assuming we've applied the execution side of this barrier, we update just the write
706 // The || implements the "dependency chain" logic for this barrier
John Zulauf36bcf6a2020-02-03 15:12:52 -0700707 if ((src_access_scope & last_write) || (write_dependency_chain & src_exec_scope)) {
708 write_barriers |= dst_access_scope;
709 write_dependency_chain |= dst_exec_scope;
John Zulauf9cb530d2019-09-30 14:14:10 -0600710 }
711}
712
713void SyncValidator::ResetCommandBuffer(VkCommandBuffer command_buffer) {
John Zulauf3d84f1b2020-03-09 13:33:25 -0600714 auto *access_context = GetAccessContextNoInsert(command_buffer);
715 if (access_context) {
716 access_context->Reset();
John Zulauf9cb530d2019-09-30 14:14:10 -0600717 }
718}
719
John Zulauf3d84f1b2020-03-09 13:33:25 -0600720void SyncValidator::ApplyGlobalBarriers(AccessTrackerContext *context, VkPipelineStageFlags srcStageMask,
John Zulauf36bcf6a2020-02-03 15:12:52 -0700721 VkPipelineStageFlags dstStageMask, SyncStageAccessFlags src_access_scope,
722 SyncStageAccessFlags dst_access_scope, uint32_t memoryBarrierCount,
John Zulauf9cb530d2019-09-30 14:14:10 -0600723 const VkMemoryBarrier *pMemoryBarriers) {
724 // TODO: Implement this better (maybe some delayed/on-demand integration).
John Zulauf36bcf6a2020-02-03 15:12:52 -0700725 ApplyGlobalBarrierFunctor barriers_functor(srcStageMask, dstStageMask, src_access_scope, dst_access_scope, memoryBarrierCount,
John Zulauf9cb530d2019-09-30 14:14:10 -0600726 pMemoryBarriers);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600727 for (auto &handle_tracker_pair : context->GetAccessTrackerMap()) {
728 UpdateMemoryAccessState(&handle_tracker_pair.second.GetCurrentAccessMap(), full_range, barriers_functor);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700729 }
John Zulauf9cb530d2019-09-30 14:14:10 -0600730}
731
John Zulauf3d84f1b2020-03-09 13:33:25 -0600732void SyncValidator::ApplyBufferBarriers(AccessTrackerContext *context, VkPipelineStageFlags src_exec_scope,
John Zulauf36bcf6a2020-02-03 15:12:52 -0700733 SyncStageAccessFlags src_stage_accesses, VkPipelineStageFlags dst_exec_scope,
734 SyncStageAccessFlags dst_stage_accesses, uint32_t barrier_count,
John Zulauf9cb530d2019-09-30 14:14:10 -0600735 const VkBufferMemoryBarrier *barriers) {
736 // TODO Implement this at subresource/memory_range accuracy
737 for (uint32_t index = 0; index < barrier_count; index++) {
738 const auto &barrier = barriers[index];
739 const auto *buffer = Get<BUFFER_STATE>(barrier.buffer);
740 if (!buffer) continue;
John Zulauf3d84f1b2020-03-09 13:33:25 -0600741 auto *tracker = context->GetAccessTracker(VulkanTypedHandle(buffer->binding.mem_state->mem, kVulkanObjectTypeDeviceMemory));
742 if (!tracker) continue;
John Zulauf5c5e88d2019-12-26 11:22:02 -0700743 ResourceAccessRange range = MakeMemoryAccessRange(*buffer, barrier.offset, barrier.size);
John Zulauf9cb530d2019-09-30 14:14:10 -0600744 UpdateMemoryAccessState(
John Zulauf3d84f1b2020-03-09 13:33:25 -0600745 &tracker->GetCurrentAccessMap(), range,
John Zulauf36bcf6a2020-02-03 15:12:52 -0700746 ApplyMemoryAccessBarrierFunctor(src_exec_scope, AccessScope(src_stage_accesses, barrier.srcAccessMask), dst_exec_scope,
747 AccessScope(dst_stage_accesses, barrier.dstAccessMask)));
John Zulauf9cb530d2019-09-30 14:14:10 -0600748 }
749}
750
John Zulauf3d84f1b2020-03-09 13:33:25 -0600751void SyncValidator::ApplyImageBarriers(AccessTrackerContext *context, VkPipelineStageFlags src_exec_scope,
John Zulauf36bcf6a2020-02-03 15:12:52 -0700752 SyncStageAccessFlags src_stage_accesses, VkPipelineStageFlags dst_exec_scope,
753 SyncStageAccessFlags dst_stage_accesses, uint32_t barrier_count,
John Zulauf5c5e88d2019-12-26 11:22:02 -0700754 const VkImageMemoryBarrier *barriers) {
755 for (uint32_t index = 0; index < barrier_count; index++) {
756 const auto &barrier = barriers[index];
757 const auto *image = Get<IMAGE_STATE>(barrier.image);
758 if (!image) continue;
John Zulauf3d84f1b2020-03-09 13:33:25 -0600759 auto tracker = context->GetAccessTrackerNoInsert(VulkanTypedHandle(barrier.image, kVulkanObjectTypeImage));
760 if (!tracker) continue;
761 auto *accesses = &tracker->GetCurrentAccessMap();
762
John Zulauf5c5e88d2019-12-26 11:22:02 -0700763 auto subresource_range = NormalizeSubresourceRange(image->createInfo, barrier.subresourceRange);
locke-lunarg1dbbb9e2020-02-28 22:43:53 -0700764 VkImageSubresourceLayers subresource_layers = {subresource_range.aspectMask, 0, subresource_range.baseArrayLayer,
765 subresource_range.layerCount};
766 for (uint32_t mip_index = subresource_range.baseMipLevel; mip_index < subresource_range.levelCount; mip_index++) {
767 subresource_layers.mipLevel = mip_index;
768 VkExtent3D subresource_extent = GetImageSubresourceExtent(image, &subresource_layers);
769 subresource_adapter::OffsetRangeEncoder encoder(image->full_range, subresource_extent);
770 subresource_adapter::OffsetRangeGenerator range_gen(encoder, subresource_range, {0, 0}, subresource_extent);
771
772 const ApplyMemoryAccessBarrierFunctor barrier_action(
773 src_exec_scope, AccessScope(src_stage_accesses, barrier.srcAccessMask), dst_exec_scope,
774 AccessScope(dst_stage_accesses, barrier.dstAccessMask));
775 for (; range_gen->non_empty(); ++range_gen) {
776 UpdateMemoryAccessState(accesses, *range_gen, barrier_action);
777 }
John Zulauf5c5e88d2019-12-26 11:22:02 -0700778 }
John Zulauf9cb530d2019-09-30 14:14:10 -0600779 }
John Zulauf9cb530d2019-09-30 14:14:10 -0600780}
781
782bool SyncValidator::PreCallValidateCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
783 uint32_t regionCount, const VkBufferCopy *pRegions) const {
784 bool skip = false;
John Zulauf3d84f1b2020-03-09 13:33:25 -0600785 const auto *cb_context = GetAccessContext(commandBuffer);
786 assert(cb_context);
787 if (!cb_context) return skip;
788 const auto *context = cb_context->GetCurrentAccessContext();
John Zulauf9cb530d2019-09-30 14:14:10 -0600789
John Zulauf3d84f1b2020-03-09 13:33:25 -0600790 // If we have no previous accesses, we have no hazards
791 // TODO: make this sub-resource capable
792 // TODO: make this general, and stuff it into templates/utility functions
793 const auto *src_buffer = Get<BUFFER_STATE>(srcBuffer);
794 const auto src_mem = (src_buffer && !src_buffer->sparse) ? src_buffer->binding.mem_state->mem : VK_NULL_HANDLE;
795 const auto *dst_buffer = Get<BUFFER_STATE>(dstBuffer);
796 const auto dst_mem = (dst_buffer && !dst_buffer->sparse) ? dst_buffer->binding.mem_state->mem : VK_NULL_HANDLE;
797
798 for (uint32_t region = 0; region < regionCount; region++) {
799 const auto &copy_region = pRegions[region];
800 if (src_mem != VK_NULL_HANDLE) {
801 ResourceAccessRange src_range = MakeMemoryAccessRange(*src_buffer, copy_region.srcOffset, copy_region.size);
802 auto hazard = context->DetectHazard(VulkanTypedHandle(src_mem, kVulkanObjectTypeDeviceMemory),
803 SYNC_TRANSFER_TRANSFER_READ, src_range);
804 if (hazard.hazard) {
805 // TODO -- add tag information to log msg when useful.
locke-lunarga0003652020-03-10 11:38:51 -0600806 skip |= LogError(srcBuffer, string_SyncHazardVUID(hazard.hazard),
807 "vkCmdCopyBuffer: Hazard %s for srcBuffer %s, region %" PRIu32, string_SyncHazard(hazard.hazard),
808 report_data->FormatHandle(srcBuffer).c_str(), region);
John Zulauf9cb530d2019-09-30 14:14:10 -0600809 }
John Zulauf9cb530d2019-09-30 14:14:10 -0600810 }
John Zulauf3d84f1b2020-03-09 13:33:25 -0600811 if ((dst_mem != VK_NULL_HANDLE) && !skip) {
812 ResourceAccessRange dst_range = MakeMemoryAccessRange(*dst_buffer, copy_region.dstOffset, copy_region.size);
813 auto hazard = context->DetectHazard(VulkanTypedHandle(dst_mem, kVulkanObjectTypeDeviceMemory),
814 SYNC_TRANSFER_TRANSFER_WRITE, dst_range);
815 if (hazard.hazard) {
locke-lunarga0003652020-03-10 11:38:51 -0600816 skip |= LogError(dstBuffer, string_SyncHazardVUID(hazard.hazard),
817 "vkCmdCopyBuffer: Hazard %s for dstBuffer %s, region %" PRIu32, string_SyncHazard(hazard.hazard),
818 report_data->FormatHandle(dstBuffer).c_str(), region);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600819 }
820 }
821 if (skip) break;
John Zulauf9cb530d2019-09-30 14:14:10 -0600822 }
823 return skip;
824}
825
826void SyncValidator::PreCallRecordCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
827 uint32_t regionCount, const VkBufferCopy *pRegions) {
John Zulauf3d84f1b2020-03-09 13:33:25 -0600828 auto *cb_context = GetAccessContext(commandBuffer);
829 assert(cb_context);
830 auto *context = cb_context->GetCurrentAccessContext();
831
John Zulauf9cb530d2019-09-30 14:14:10 -0600832 const auto *src_buffer = Get<BUFFER_STATE>(srcBuffer);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600833 const auto src_mem = (src_buffer && !src_buffer->sparse) ? src_buffer->binding.mem_state->mem : VK_NULL_HANDLE;
834 const VulkanTypedHandle src_handle(src_mem, kVulkanObjectTypeDeviceMemory);
835 AccessTracker *src_tracker = src_mem ? context->GetAccessTracker(src_handle) : nullptr;
836
John Zulauf9cb530d2019-09-30 14:14:10 -0600837 const auto *dst_buffer = Get<BUFFER_STATE>(dstBuffer);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600838 const auto dst_mem = (dst_buffer && !dst_buffer->sparse) ? dst_buffer->binding.mem_state->mem : VK_NULL_HANDLE;
839 const VulkanTypedHandle dst_handle(dst_mem, kVulkanObjectTypeDeviceMemory);
840 AccessTracker *dst_tracker = dst_mem ? context->GetAccessTracker(dst_handle) : nullptr;
John Zulauf9cb530d2019-09-30 14:14:10 -0600841
842 for (uint32_t region = 0; region < regionCount; region++) {
843 const auto &copy_region = pRegions[region];
John Zulauf3d84f1b2020-03-09 13:33:25 -0600844 if (src_mem) {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700845 ResourceAccessRange src_range = MakeMemoryAccessRange(*src_buffer, copy_region.srcOffset, copy_region.size);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600846 src_tracker->UpdateAccessState(SYNC_TRANSFER_TRANSFER_READ, src_range, tag);
John Zulauf9cb530d2019-09-30 14:14:10 -0600847 }
John Zulauf3d84f1b2020-03-09 13:33:25 -0600848 if (dst_mem) {
John Zulauf5c5e88d2019-12-26 11:22:02 -0700849 ResourceAccessRange dst_range = MakeMemoryAccessRange(*dst_buffer, copy_region.dstOffset, copy_region.size);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600850 dst_tracker->UpdateAccessState(SYNC_TRANSFER_TRANSFER_WRITE, dst_range, tag);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700851 }
852 }
853}
854
855bool SyncValidator::PreCallValidateCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
856 VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
857 const VkImageCopy *pRegions) const {
858 bool skip = false;
John Zulauf3d84f1b2020-03-09 13:33:25 -0600859 const auto *cb_access_context = GetAccessContext(commandBuffer);
860 assert(cb_access_context);
861 if (!cb_access_context) return skip;
John Zulauf5c5e88d2019-12-26 11:22:02 -0700862
John Zulauf3d84f1b2020-03-09 13:33:25 -0600863 const auto *context = cb_access_context->GetCurrentAccessContext();
864 assert(context);
865 if (!context) return skip;
866
867 const auto *src_image = Get<IMAGE_STATE>(srcImage);
868 const auto *dst_image = Get<IMAGE_STATE>(dstImage);
869
870 for (uint32_t region = 0; region < regionCount; region++) {
871 const auto &copy_region = pRegions[region];
872 if (src_image) {
873 auto hazard = context->DetectHazard(*src_image, SYNC_TRANSFER_TRANSFER_READ, copy_region.srcSubresource,
874 copy_region.srcOffset, copy_region.extent);
875 if (hazard.hazard) {
locke-lunarga0003652020-03-10 11:38:51 -0600876 skip |= LogError(srcImage, string_SyncHazardVUID(hazard.hazard),
877 "vkCmdCopyImage: Hazard %s for srcImage %s, region %" PRIu32, string_SyncHazard(hazard.hazard),
878 report_data->FormatHandle(srcImage).c_str(), region);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700879 }
John Zulauf3d84f1b2020-03-09 13:33:25 -0600880 }
881
882 if (dst_image) {
locke-lunarg1df1f882020-03-02 16:42:08 -0700883 VkExtent3D dst_copy_extent =
884 GetAdjustedDestImageExtent(src_image->createInfo.format, dst_image->createInfo.format, copy_region.extent);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600885 auto hazard = context->DetectHazard(*dst_image, SYNC_TRANSFER_TRANSFER_WRITE, copy_region.dstSubresource,
locke-lunarg1df1f882020-03-02 16:42:08 -0700886 copy_region.dstOffset, dst_copy_extent);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600887 if (hazard.hazard) {
locke-lunarga0003652020-03-10 11:38:51 -0600888 skip |= LogError(dstImage, string_SyncHazardVUID(hazard.hazard),
889 "vkCmdCopyImage: Hazard %s for dstImage %s, region %" PRIu32, string_SyncHazard(hazard.hazard),
890 report_data->FormatHandle(dstImage).c_str(), region);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700891 }
locke-lunarg1dbbb9e2020-02-28 22:43:53 -0700892 if (skip) break;
John Zulauf5c5e88d2019-12-26 11:22:02 -0700893 }
894 }
John Zulauf3d84f1b2020-03-09 13:33:25 -0600895
John Zulauf5c5e88d2019-12-26 11:22:02 -0700896 return skip;
897}
898
899void SyncValidator::PreCallRecordCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
900 VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
901 const VkImageCopy *pRegions) {
John Zulauf3d84f1b2020-03-09 13:33:25 -0600902 auto *cb_access_context = GetAccessContext(commandBuffer);
903 assert(cb_access_context);
904 auto *context = cb_access_context->GetCurrentAccessContext();
905 assert(context);
906
John Zulauf5c5e88d2019-12-26 11:22:02 -0700907 auto *src_image = Get<IMAGE_STATE>(srcImage);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600908 auto *src_tracker = context->GetAccessTracker(VulkanTypedHandle(srcImage, kVulkanObjectTypeImage));
John Zulauf5c5e88d2019-12-26 11:22:02 -0700909 auto *dst_image = Get<IMAGE_STATE>(dstImage);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600910 auto *dst_tracker = context->GetAccessTracker(VulkanTypedHandle(dstImage, kVulkanObjectTypeImage));
John Zulauf5c5e88d2019-12-26 11:22:02 -0700911
912 for (uint32_t region = 0; region < regionCount; region++) {
913 const auto &copy_region = pRegions[region];
John Zulauf3d84f1b2020-03-09 13:33:25 -0600914 if (src_image) {
915 src_tracker->UpdateAccessState(*src_image, SYNC_TRANSFER_TRANSFER_READ, copy_region.srcSubresource,
916 copy_region.srcOffset, copy_region.extent, tag);
John Zulauf5c5e88d2019-12-26 11:22:02 -0700917 }
John Zulauf3d84f1b2020-03-09 13:33:25 -0600918 if (dst_image) {
locke-lunarg1df1f882020-03-02 16:42:08 -0700919 VkExtent3D dst_copy_extent =
920 GetAdjustedDestImageExtent(src_image->createInfo.format, dst_image->createInfo.format, copy_region.extent);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600921 dst_tracker->UpdateAccessState(*dst_image, SYNC_TRANSFER_TRANSFER_WRITE, copy_region.dstSubresource,
locke-lunarg1df1f882020-03-02 16:42:08 -0700922 copy_region.dstOffset, dst_copy_extent, tag);
John Zulauf9cb530d2019-09-30 14:14:10 -0600923 }
924 }
925}
926
927bool SyncValidator::PreCallValidateCmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask,
928 VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags,
929 uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
930 uint32_t bufferMemoryBarrierCount,
931 const VkBufferMemoryBarrier *pBufferMemoryBarriers,
932 uint32_t imageMemoryBarrierCount,
933 const VkImageMemoryBarrier *pImageMemoryBarriers) 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 Zulauf0cb5be22020-01-23 12:18:22 -0700938
John Zulauf3d84f1b2020-03-09 13:33:25 -0600939 const auto *context = cb_access_context->GetCurrentAccessContext();
940 assert(context);
941 if (!context) return skip;
John Zulauf0cb5be22020-01-23 12:18:22 -0700942
John Zulauf3d84f1b2020-03-09 13:33:25 -0600943 const auto src_stage_mask = ExpandPipelineStages(cb_access_context->GetQueueFlags(), srcStageMask);
John Zulauf36bcf6a2020-02-03 15:12:52 -0700944 const auto src_exec_scope = WithEarlierPipelineStages(src_stage_mask);
945 auto src_stage_accesses = AccessScopeByStage(src_stage_mask);
John Zulauf0cb5be22020-01-23 12:18:22 -0700946 // Validate Image Layout transitions
947 for (uint32_t index = 0; index < imageMemoryBarrierCount; index++) {
948 const auto &barrier = pImageMemoryBarriers[index];
949 if (barrier.newLayout == barrier.oldLayout) continue; // Only interested in layout transitions at this point.
950 const auto *image_state = Get<IMAGE_STATE>(barrier.image);
951 if (!image_state) continue;
John Zulauf3d84f1b2020-03-09 13:33:25 -0600952 const auto hazard = DetectImageBarrierHazard(*context, *image_state, src_exec_scope, src_stage_accesses, barrier);
John Zulauf0cb5be22020-01-23 12:18:22 -0700953 if (hazard.hazard) {
954 // TODO -- add tag information to log msg when useful.
locke-lunarga0003652020-03-10 11:38:51 -0600955 skip |= LogError(barrier.image, string_SyncHazardVUID(hazard.hazard),
956 "vkCmdPipelineBarrier: Hazard %s for image barrier %" PRIu32 " %s", string_SyncHazard(hazard.hazard),
957 index, report_data->FormatHandle(barrier.image).c_str());
John Zulauf0cb5be22020-01-23 12:18:22 -0700958 }
959 }
John Zulauf9cb530d2019-09-30 14:14:10 -0600960
961 return skip;
962}
963
964void SyncValidator::PreCallRecordCmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask,
965 VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags,
966 uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
967 uint32_t bufferMemoryBarrierCount,
968 const VkBufferMemoryBarrier *pBufferMemoryBarriers,
969 uint32_t imageMemoryBarrierCount,
970 const VkImageMemoryBarrier *pImageMemoryBarriers) {
John Zulauf3d84f1b2020-03-09 13:33:25 -0600971 auto *cb_access_context = GetAccessContext(commandBuffer);
972 assert(cb_access_context);
973 if (!cb_access_context) return;
974 auto access_context = cb_access_context->GetCurrentAccessContext();
975 assert(access_context);
976 if (!access_context) return;
John Zulauf9cb530d2019-09-30 14:14:10 -0600977
John Zulauf3d84f1b2020-03-09 13:33:25 -0600978 const auto src_stage_mask = ExpandPipelineStages(cb_access_context->GetQueueFlags(), srcStageMask);
John Zulauf36bcf6a2020-02-03 15:12:52 -0700979 auto src_stage_accesses = AccessScopeByStage(src_stage_mask);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600980 const auto dst_stage_mask = ExpandPipelineStages(cb_access_context->GetQueueFlags(), dstStageMask);
John Zulauf36bcf6a2020-02-03 15:12:52 -0700981 auto dst_stage_accesses = AccessScopeByStage(dst_stage_mask);
982 const auto src_exec_scope = WithEarlierPipelineStages(src_stage_mask);
983 const auto dst_exec_scope = WithLaterPipelineStages(dst_stage_mask);
John Zulauf3d84f1b2020-03-09 13:33:25 -0600984 ApplyBufferBarriers(access_context, src_exec_scope, src_stage_accesses, dst_exec_scope, dst_stage_accesses,
985 bufferMemoryBarrierCount, pBufferMemoryBarriers);
986 ApplyImageBarriers(access_context, src_exec_scope, src_stage_accesses, dst_exec_scope, dst_stage_accesses,
987 imageMemoryBarrierCount, pImageMemoryBarriers);
John Zulauf9cb530d2019-09-30 14:14:10 -0600988
989 // 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 -0600990 ApplyGlobalBarriers(access_context, src_exec_scope, dst_exec_scope, src_stage_accesses, dst_stage_accesses, memoryBarrierCount,
John Zulauf0cb5be22020-01-23 12:18:22 -0700991 pMemoryBarriers);
John Zulauf9cb530d2019-09-30 14:14:10 -0600992}
993
994void SyncValidator::PostCallRecordCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo *pCreateInfo,
995 const VkAllocationCallbacks *pAllocator, VkDevice *pDevice, VkResult result) {
996 // The state tracker sets up the device state
997 StateTracker::PostCallRecordCreateDevice(gpu, pCreateInfo, pAllocator, pDevice, result);
998
999 // Add the callback hooks for the functions that are either broadly or deeply used and that the ValidationStateTracker refactor
1000 // would be messier without.
1001 // TODO: Find a good way to do this hooklessly.
1002 ValidationObject *device_object = GetLayerDataPtr(get_dispatch_key(*pDevice), layer_data_map);
1003 ValidationObject *validation_data = GetValidationObject(device_object->object_dispatch, LayerObjectTypeSyncValidation);
1004 SyncValidator *sync_device_state = static_cast<SyncValidator *>(validation_data);
1005
1006 sync_device_state->SetCommandBufferResetCallback(
1007 [sync_device_state](VkCommandBuffer command_buffer) -> void { sync_device_state->ResetCommandBuffer(command_buffer); });
1008}
John Zulauf3d84f1b2020-03-09 13:33:25 -06001009
1010void SyncValidator::PostCallRecordBeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo,
1011 VkResult result) {
1012 // The state tracker sets up the command buffer state
1013 StateTracker::PostCallRecordBeginCommandBuffer(commandBuffer, pBeginInfo, result);
1014
1015 // Create/initialize the structure that trackers accesses at the command buffer scope.
1016 auto cb_access_context = GetAccessContext(commandBuffer);
1017 assert(cb_access_context);
1018 cb_access_context->Reset();
1019}
1020
1021void SyncValidator::RecordCmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
1022 const VkSubpassBeginInfo *pSubpassBeginInfo) {
1023 const auto rp_state = Get<RENDER_PASS_STATE>(pRenderPassBegin->renderPass);
1024 auto cb_context = GetAccessContext(commandBuffer);
1025 if (rp_state && cb_context) {
1026 cb_context->BeginRenderPass(*rp_state);
1027 }
1028}
1029
1030void SyncValidator::PostCallRecordCmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
1031 VkSubpassContents contents) {
1032 StateTracker::PostCallRecordCmdBeginRenderPass(commandBuffer, pRenderPassBegin, contents);
1033 auto subpass_begin_info = lvl_init_struct<VkSubpassBeginInfo>();
1034 subpass_begin_info.contents = contents;
1035 RecordCmdBeginRenderPass(commandBuffer, pRenderPassBegin, &subpass_begin_info);
1036}
1037
1038void SyncValidator::PostCallRecordCmdBeginRenderPass2(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
1039 const VkSubpassBeginInfo *pSubpassBeginInfo) {
1040 StateTracker::PostCallRecordCmdBeginRenderPass2(commandBuffer, pRenderPassBegin, pSubpassBeginInfo);
1041 RecordCmdBeginRenderPass(commandBuffer, pRenderPassBegin, pSubpassBeginInfo);
1042}
1043
1044void SyncValidator::PostCallRecordCmdBeginRenderPass2KHR(VkCommandBuffer commandBuffer,
1045 const VkRenderPassBeginInfo *pRenderPassBegin,
1046 const VkSubpassBeginInfo *pSubpassBeginInfo) {
1047 StateTracker::PostCallRecordCmdBeginRenderPass2KHR(commandBuffer, pRenderPassBegin, pSubpassBeginInfo);
1048 RecordCmdBeginRenderPass(commandBuffer, pRenderPassBegin, pSubpassBeginInfo);
1049}
1050
1051void SyncValidator::RecordCmdNextSubpass(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo *pSubpassBeginInfo,
1052 const VkSubpassEndInfo *pSubpassEndInfo) {
1053 auto cb_context = GetAccessContext(commandBuffer);
1054 assert(cb_context);
1055 auto cb_state = cb_context->GetCommandBufferState();
1056 if (!cb_state) return;
1057
1058 auto rp_state = cb_state->activeRenderPass;
1059 if (!rp_state) return;
1060
1061 cb_context->NextRenderPass(*rp_state);
1062}
1063
1064void SyncValidator::PostCallRecordCmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents) {
1065 StateTracker::PostCallRecordCmdNextSubpass(commandBuffer, contents);
1066 auto subpass_begin_info = lvl_init_struct<VkSubpassBeginInfo>();
1067 subpass_begin_info.contents = contents;
1068 RecordCmdNextSubpass(commandBuffer, &subpass_begin_info, nullptr);
1069}
1070
1071void SyncValidator::PostCallRecordCmdNextSubpass2(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo *pSubpassBeginInfo,
1072 const VkSubpassEndInfo *pSubpassEndInfo) {
1073 StateTracker::PostCallRecordCmdNextSubpass2(commandBuffer, pSubpassBeginInfo, pSubpassEndInfo);
1074 RecordCmdNextSubpass(commandBuffer, pSubpassBeginInfo, pSubpassEndInfo);
1075}
1076
1077void SyncValidator::PostCallRecordCmdNextSubpass2KHR(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo *pSubpassBeginInfo,
1078 const VkSubpassEndInfo *pSubpassEndInfo) {
1079 StateTracker::PostCallRecordCmdNextSubpass2KHR(commandBuffer, pSubpassBeginInfo, pSubpassEndInfo);
1080 RecordCmdNextSubpass(commandBuffer, pSubpassBeginInfo, pSubpassEndInfo);
1081}
1082
1083void SyncValidator::RecordCmdEndRenderPass(VkCommandBuffer commandBuffer, const VkSubpassEndInfo *pSubpassEndInfo) {}
1084
1085void SyncValidator::PostCallRecordCmdEndRenderPass(VkCommandBuffer commandBuffer) {
1086 StateTracker::PostCallRecordCmdEndRenderPass(commandBuffer);
1087 RecordCmdEndRenderPass(commandBuffer, nullptr);
1088}
1089
1090void SyncValidator::PostCallRecordCmdEndRenderPass2(VkCommandBuffer commandBuffer, const VkSubpassEndInfo *pSubpassEndInfo) {
1091 StateTracker::PostCallRecordCmdEndRenderPass2(commandBuffer, pSubpassEndInfo);
1092 RecordCmdEndRenderPass(commandBuffer, pSubpassEndInfo);
1093}
1094
1095void SyncValidator::PostCallRecordCmdEndRenderPass2KHR(VkCommandBuffer commandBuffer, const VkSubpassEndInfo *pSubpassEndInfo) {
1096 StateTracker::PostCallRecordCmdEndRenderPass2KHR(commandBuffer, pSubpassEndInfo);
1097 RecordCmdEndRenderPass(commandBuffer, pSubpassEndInfo);
1098}
locke-lunarga19c71d2020-03-02 18:17:04 -07001099
1100bool SyncValidator::PreCallValidateCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage,
1101 VkImageLayout dstImageLayout, uint32_t regionCount,
1102 const VkBufferImageCopy *pRegions) const {
1103 bool skip = false;
1104 const auto *cb_access_context = GetAccessContext(commandBuffer);
1105 assert(cb_access_context);
1106 if (!cb_access_context) return skip;
1107
1108 const auto *context = cb_access_context->GetCurrentAccessContext();
1109 assert(context);
1110 if (!context) return skip;
1111
1112 const auto *src_buffer = Get<BUFFER_STATE>(srcBuffer);
1113 const auto src_mem = (src_buffer && !src_buffer->sparse) ? src_buffer->binding.mem_state->mem : VK_NULL_HANDLE;
1114 const auto *dst_image = Get<IMAGE_STATE>(dstImage);
1115
1116 for (uint32_t region = 0; region < regionCount; region++) {
1117 const auto &copy_region = pRegions[region];
1118 if (src_mem) {
1119 ResourceAccessRange src_range = MakeMemoryAccessRange(
1120 *src_buffer, copy_region.bufferOffset, GetBufferSizeFromCopyImage(copy_region, dst_image->createInfo.format));
1121 auto hazard = context->DetectHazard(VulkanTypedHandle(src_mem, kVulkanObjectTypeDeviceMemory),
1122 SYNC_TRANSFER_TRANSFER_READ, src_range);
1123 if (hazard.hazard) {
1124 // TODO -- add tag information to log msg when useful.
locke-lunarga0003652020-03-10 11:38:51 -06001125 skip |= LogError(srcBuffer, string_SyncHazardVUID(hazard.hazard),
1126 "vkCmdCopyBufferToImage: Hazard %s for srcBuffer %s, region %" PRIu32,
locke-lunarga19c71d2020-03-02 18:17:04 -07001127 string_SyncHazard(hazard.hazard), report_data->FormatHandle(srcBuffer).c_str(), region);
1128 }
1129 }
1130 if (dst_image) {
1131 auto hazard = context->DetectHazard(*dst_image, SYNC_TRANSFER_TRANSFER_WRITE, copy_region.imageSubresource,
1132 copy_region.imageOffset, copy_region.imageExtent);
1133 if (hazard.hazard) {
locke-lunarga0003652020-03-10 11:38:51 -06001134 skip |= LogError(dstImage, string_SyncHazardVUID(hazard.hazard),
1135 "vkCmdCopyBufferToImage: Hazard %s for dstImage %s, region %" PRIu32,
locke-lunarga19c71d2020-03-02 18:17:04 -07001136 string_SyncHazard(hazard.hazard), report_data->FormatHandle(dstImage).c_str(), region);
1137 }
1138 if (skip) break;
1139 }
1140 if (skip) break;
1141 }
1142 return skip;
1143}
1144
1145void SyncValidator::PreCallRecordCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage,
1146 VkImageLayout dstImageLayout, uint32_t regionCount,
1147 const VkBufferImageCopy *pRegions) {
1148 auto *cb_access_context = GetAccessContext(commandBuffer);
1149 assert(cb_access_context);
1150 auto *context = cb_access_context->GetCurrentAccessContext();
1151 assert(context);
1152
1153 const auto *src_buffer = Get<BUFFER_STATE>(srcBuffer);
1154 const auto src_mem = (src_buffer && !src_buffer->sparse) ? src_buffer->binding.mem_state->mem : VK_NULL_HANDLE;
1155 const VulkanTypedHandle src_handle(src_mem, kVulkanObjectTypeDeviceMemory);
1156 AccessTracker *src_tracker = src_mem ? context->GetAccessTracker(src_handle) : nullptr;
1157 auto *dst_image = Get<IMAGE_STATE>(dstImage);
1158 auto *dst_tracker = context->GetAccessTracker(VulkanTypedHandle(dstImage, kVulkanObjectTypeImage));
1159
1160 for (uint32_t region = 0; region < regionCount; region++) {
1161 const auto &copy_region = pRegions[region];
1162 if (src_buffer) {
1163 ResourceAccessRange src_range = MakeMemoryAccessRange(
1164 *src_buffer, copy_region.bufferOffset, GetBufferSizeFromCopyImage(copy_region, dst_image->createInfo.format));
1165 src_tracker->UpdateAccessState(SYNC_TRANSFER_TRANSFER_READ, src_range, tag);
1166 }
1167 if (dst_image) {
1168 dst_tracker->UpdateAccessState(*dst_image, SYNC_TRANSFER_TRANSFER_WRITE, copy_region.imageSubresource,
1169 copy_region.imageOffset, copy_region.imageExtent, tag);
1170 }
1171 }
1172}
1173
1174bool SyncValidator::PreCallValidateCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage,
1175 VkImageLayout srcImageLayout, VkBuffer dstBuffer, 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_image = Get<IMAGE_STATE>(srcImage);
1187 const auto *dst_buffer = Get<BUFFER_STATE>(dstBuffer);
1188 const auto dst_mem = (dst_buffer && !dst_buffer->sparse) ? dst_buffer->binding.mem_state->mem : VK_NULL_HANDLE;
1189 for (uint32_t region = 0; region < regionCount; region++) {
1190 const auto &copy_region = pRegions[region];
1191 if (src_image) {
1192 auto hazard = context->DetectHazard(*src_image, SYNC_TRANSFER_TRANSFER_READ, copy_region.imageSubresource,
1193 copy_region.imageOffset, copy_region.imageExtent);
1194 if (hazard.hazard) {
locke-lunarga0003652020-03-10 11:38:51 -06001195 skip |= LogError(srcImage, string_SyncHazardVUID(hazard.hazard),
1196 "vkCmdCopyImageToBuffer: Hazard %s for srcImage %s, region %" PRIu32,
locke-lunarga19c71d2020-03-02 18:17:04 -07001197 string_SyncHazard(hazard.hazard), report_data->FormatHandle(srcImage).c_str(), region);
1198 }
1199 }
1200 if (dst_mem) {
1201 ResourceAccessRange dst_range = MakeMemoryAccessRange(
1202 *dst_buffer, copy_region.bufferOffset, GetBufferSizeFromCopyImage(copy_region, src_image->createInfo.format));
1203 auto hazard = context->DetectHazard(VulkanTypedHandle(dst_mem, kVulkanObjectTypeDeviceMemory),
1204 SYNC_TRANSFER_TRANSFER_WRITE, dst_range);
1205 if (hazard.hazard) {
locke-lunarga0003652020-03-10 11:38:51 -06001206 skip |= LogError(dstBuffer, string_SyncHazardVUID(hazard.hazard),
1207 "vkCmdCopyImageToBuffer: Hazard %s for dstBuffer %s, region %" PRIu32,
locke-lunarga19c71d2020-03-02 18:17:04 -07001208 string_SyncHazard(hazard.hazard), report_data->FormatHandle(dstBuffer).c_str(), region);
1209 }
1210 }
1211 if (skip) break;
1212 }
1213 return skip;
1214}
1215
1216void SyncValidator::PreCallRecordCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
1217 VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy *pRegions) {
1218 auto *cb_access_context = GetAccessContext(commandBuffer);
1219 assert(cb_access_context);
1220 auto *context = cb_access_context->GetCurrentAccessContext();
1221 assert(context);
1222
1223 const auto *src_image = Get<IMAGE_STATE>(srcImage);
1224 auto *src_tracker = context->GetAccessTracker(VulkanTypedHandle(srcImage, kVulkanObjectTypeImage));
1225 auto *dst_buffer = Get<BUFFER_STATE>(dstBuffer);
1226 const auto dst_mem = (dst_buffer && !dst_buffer->sparse) ? dst_buffer->binding.mem_state->mem : VK_NULL_HANDLE;
1227 const VulkanTypedHandle src_handle(dst_mem, kVulkanObjectTypeDeviceMemory);
1228 AccessTracker *dst_tracker = dst_mem ? context->GetAccessTracker(src_handle) : nullptr;
1229
1230 for (uint32_t region = 0; region < regionCount; region++) {
1231 const auto &copy_region = pRegions[region];
1232 if (src_image) {
1233 src_tracker->UpdateAccessState(*src_image, SYNC_TRANSFER_TRANSFER_READ, copy_region.imageSubresource,
1234 copy_region.imageOffset, copy_region.imageExtent, tag);
1235 }
1236 if (dst_buffer) {
1237 ResourceAccessRange dst_range = MakeMemoryAccessRange(
1238 *dst_buffer, copy_region.bufferOffset, GetBufferSizeFromCopyImage(copy_region, src_image->createInfo.format));
1239 dst_tracker->UpdateAccessState(SYNC_TRANSFER_TRANSFER_WRITE, dst_range, tag);
1240 }
1241 }
1242}
1243
1244bool SyncValidator::PreCallValidateCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
1245 VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
1246 const VkImageBlit *pRegions, VkFilter filter) const {
1247 bool skip = false;
1248 const auto *cb_access_context = GetAccessContext(commandBuffer);
1249 assert(cb_access_context);
1250 if (!cb_access_context) return skip;
1251
1252 const auto *context = cb_access_context->GetCurrentAccessContext();
1253 assert(context);
1254 if (!context) return skip;
1255
1256 const auto *src_image = Get<IMAGE_STATE>(srcImage);
1257 const auto *dst_image = Get<IMAGE_STATE>(dstImage);
1258
1259 for (uint32_t region = 0; region < regionCount; region++) {
1260 const auto &blit_region = pRegions[region];
1261 if (src_image) {
1262 VkExtent3D extent = {static_cast<uint32_t>(blit_region.srcOffsets[1].x - blit_region.srcOffsets[0].x),
1263 static_cast<uint32_t>(blit_region.srcOffsets[1].y - blit_region.srcOffsets[0].y),
1264 static_cast<uint32_t>(blit_region.srcOffsets[1].z - blit_region.srcOffsets[0].z)};
1265 auto hazard = context->DetectHazard(*src_image, SYNC_TRANSFER_TRANSFER_READ, blit_region.srcSubresource,
1266 blit_region.srcOffsets[0], extent);
1267 if (hazard.hazard) {
locke-lunarga0003652020-03-10 11:38:51 -06001268 skip |= LogError(srcImage, string_SyncHazardVUID(hazard.hazard),
1269 "vkCmdBlitImage: Hazard %s for srcImage %s, region %" PRIu32, string_SyncHazard(hazard.hazard),
1270 report_data->FormatHandle(srcImage).c_str(), region);
locke-lunarga19c71d2020-03-02 18:17:04 -07001271 }
1272 }
1273
1274 if (dst_image) {
1275 VkExtent3D extent = {static_cast<uint32_t>(blit_region.dstOffsets[1].x - blit_region.dstOffsets[0].x),
1276 static_cast<uint32_t>(blit_region.dstOffsets[1].y - blit_region.dstOffsets[0].y),
1277 static_cast<uint32_t>(blit_region.dstOffsets[1].z - blit_region.dstOffsets[0].z)};
1278 auto hazard = context->DetectHazard(*dst_image, SYNC_TRANSFER_TRANSFER_WRITE, blit_region.dstSubresource,
1279 blit_region.dstOffsets[0], extent);
1280 if (hazard.hazard) {
locke-lunarga0003652020-03-10 11:38:51 -06001281 skip |= LogError(dstImage, string_SyncHazardVUID(hazard.hazard),
1282 "vkCmdBlitImage: Hazard %s for dstImage %s, region %" PRIu32, string_SyncHazard(hazard.hazard),
1283 report_data->FormatHandle(dstImage).c_str(), region);
locke-lunarga19c71d2020-03-02 18:17:04 -07001284 }
1285 if (skip) break;
1286 }
1287 }
1288
1289 return skip;
1290}
1291
1292void SyncValidator::PreCallRecordCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
1293 VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
1294 const VkImageBlit *pRegions, VkFilter filter) {
1295 auto *cb_access_context = GetAccessContext(commandBuffer);
1296 assert(cb_access_context);
1297 auto *context = cb_access_context->GetCurrentAccessContext();
1298 assert(context);
1299
1300 auto *src_image = Get<IMAGE_STATE>(srcImage);
1301 auto *src_tracker = context->GetAccessTracker(VulkanTypedHandle(srcImage, kVulkanObjectTypeImage));
1302 auto *dst_image = Get<IMAGE_STATE>(dstImage);
1303 auto *dst_tracker = context->GetAccessTracker(VulkanTypedHandle(dstImage, kVulkanObjectTypeImage));
1304
1305 for (uint32_t region = 0; region < regionCount; region++) {
1306 const auto &blit_region = pRegions[region];
1307 if (src_image) {
1308 VkExtent3D extent = {static_cast<uint32_t>(blit_region.srcOffsets[1].x - blit_region.srcOffsets[0].x),
1309 static_cast<uint32_t>(blit_region.srcOffsets[1].y - blit_region.srcOffsets[0].y),
1310 static_cast<uint32_t>(blit_region.srcOffsets[1].z - blit_region.srcOffsets[0].z)};
1311 src_tracker->UpdateAccessState(*src_image, SYNC_TRANSFER_TRANSFER_READ, blit_region.srcSubresource,
1312 blit_region.srcOffsets[0], extent, tag);
1313 }
1314 if (dst_image) {
1315 VkExtent3D extent = {static_cast<uint32_t>(blit_region.dstOffsets[1].x - blit_region.dstOffsets[0].x),
1316 static_cast<uint32_t>(blit_region.dstOffsets[1].y - blit_region.dstOffsets[0].y),
1317 static_cast<uint32_t>(blit_region.dstOffsets[1].z - blit_region.dstOffsets[0].z)};
1318 dst_tracker->UpdateAccessState(*dst_image, SYNC_TRANSFER_TRANSFER_WRITE, blit_region.dstSubresource,
1319 blit_region.dstOffsets[0], extent, tag);
1320 }
1321 }
1322}