diff options
| author | Chris Forbes <chrisforbes@google.com> | 2017-04-06 16:33:46 -0700 |
|---|---|---|
| committer | Chris Forbes <chrisf@ijw.co.nz> | 2017-04-29 13:32:54 -0700 |
| commit | 789e042d9a1bd703ba14d5d450e0c5abcc3dbd8c (patch) | |
| tree | f2b5d73885f84baba0f4270412a3b5d70f67a8a0 /layers/core_validation.cpp | |
| parent | ef92acd69f8bb6bf609776d1aefbaacd76789c43 (diff) | |
| download | usermoji-789e042d9a1bd703ba14d5d450e0c5abcc3dbd8c.tar.xz | |
layers: Rewrite VerifyQueueStateToSeq to be less wasteful
When we have the same queue appearing multiple times in the dependency
tree of the operations between queue->seq and seq, we would scrub that
part of the submission list recursively, potentially to a great depth,
eventually blowing the stack.
[This used to work fine when it was done as part of RetireWorkOnQueue, as
we'd have brought queue->seq up as we went, and the recursive call would
end up doing no work.]
Instead, explicitly track where we're up to on each queue as well as
where we'd like to be, and use an explicit stack of work to do rather
than using the call stack.
Fixes crash in VkLayerTests.LongSemaphoreChain with 32k semaphores.
V2: Explain what's going on
V3: Tweak for windows build
Diffstat (limited to 'layers/core_validation.cpp')
| -rw-r--r-- | layers/core_validation.cpp | 76 |
1 files changed, 51 insertions, 25 deletions
diff --git a/layers/core_validation.cpp b/layers/core_validation.cpp index 3fe1b0df..6710388e 100644 --- a/layers/core_validation.cpp +++ b/layers/core_validation.cpp @@ -3904,38 +3904,64 @@ static void incrementResources(layer_data *dev_data, GLOBAL_CB_NODE *cb_node) { // For the given queue, verify the queue state up to the given seq number. // Currently the only check is to make sure that if there are events to be waited on prior to // a QueryReset, make sure that all such events have been signalled. -static bool VerifyQueueStateToSeq(layer_data *dev_data, QUEUE_STATE *queue, uint64_t seq) { +static bool VerifyQueueStateToSeq(layer_data *dev_data, QUEUE_STATE *initial_queue, uint64_t initial_seq) { bool skip = false; - auto queue_seq = queue->seq; - std::unordered_map<VkQueue, uint64_t> other_queue_seqs; - auto sub_it = queue->submissions.begin(); - while (queue_seq < seq) { - for (auto &wait : sub_it->waitSemaphores) { - auto &last_seq = other_queue_seqs[wait.queue]; - last_seq = std::max(last_seq, wait.seq); - } - for (auto cb : sub_it->cbs) { - auto cb_node = GetCBNode(dev_data, cb); - if (cb_node) { - for (auto queryEventsPair : cb_node->waitedEventsBeforeQueryReset) { - for (auto event : queryEventsPair.second) { - if (dev_data->eventMap[event].needsSignaled) { - skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, 0, DRAWSTATE_INVALID_QUERY, "DS", - "Cannot get query results on queryPool 0x%" PRIx64 - " with index %d which was guarded by unsignaled event 0x%" PRIx64 ".", - (uint64_t)(queryEventsPair.first.pool), queryEventsPair.first.index, (uint64_t)(event)); + + // sequence number we want to validate up to, per queue + std::unordered_map<QUEUE_STATE *, uint64_t> target_seqs { { initial_queue, initial_seq } }; + // sequence number we've completed validation for, per queue + std::unordered_map<QUEUE_STATE *, uint64_t> done_seqs; + std::vector<QUEUE_STATE *> worklist { initial_queue }; + + while (worklist.size()) { + auto queue = worklist.back(); + worklist.pop_back(); + + auto target_seq = target_seqs[queue]; + auto seq = std::max(done_seqs[queue], queue->seq); + auto sub_it = queue->submissions.begin() + int(seq - queue->seq); // seq >= queue->seq + + for (; seq < target_seq; ++sub_it, ++seq) { + for (auto &wait : sub_it->waitSemaphores) { + auto other_queue = GetQueueState(dev_data, wait.queue); + + if (other_queue == queue) + continue; // semaphores /always/ point backwards, so no point here. + + auto other_target_seq = std::max(target_seqs[other_queue], wait.seq); + auto other_done_seq = std::max(done_seqs[other_queue], other_queue->seq); + + // if this wait is for another queue, and covers new sequence + // numbers beyond what we've already validated, mark the new + // target seq and (possibly-re)add the queue to the worklist. + if (other_done_seq < other_target_seq) { + target_seqs[other_queue] = other_target_seq; + worklist.push_back(other_queue); + } + } + + for (auto cb : sub_it->cbs) { + auto cb_node = GetCBNode(dev_data, cb); + if (cb_node) { + for (auto queryEventsPair : cb_node->waitedEventsBeforeQueryReset) { + for (auto event : queryEventsPair.second) { + if (dev_data->eventMap[event].needsSignaled) { + skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, + VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT, 0, 0, DRAWSTATE_INVALID_QUERY, "DS", + "Cannot get query results on queryPool 0x%" PRIx64 + " with index %d which was guarded by unsignaled event 0x%" PRIx64 ".", + (uint64_t)(queryEventsPair.first.pool), queryEventsPair.first.index, (uint64_t)(event)); + } } } } } } - sub_it++; - queue_seq++; - } - for (auto qs : other_queue_seqs) { - skip |= VerifyQueueStateToSeq(dev_data, GetQueueState(dev_data, qs.first), qs.second); + + // finally mark the point we've now validated this queue to. + done_seqs[queue] = seq; } + return skip; } |
