blob: 516f10b7ef4306f3bf0c5c99cb0f47d0ea58fc2e [file] [log] [blame]
/* Copyright (c) 2015-2021 The Khronos Group Inc.
* Copyright (c) 2015-2021 Valve Corporation
* Copyright (c) 2015-2021 LunarG, Inc.
* Copyright (C) 2015-2021 Google Inc.
* Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Author: Courtney Goeltzenleuchter <courtneygo@google.com>
* Author: Tobin Ehlis <tobine@google.com>
* Author: Chris Forbes <chrisf@ijw.co.nz>
* Author: Mark Lobodzinski <mark@lunarg.com>
* Author: Dave Houlton <daveh@lunarg.com>
* Author: John Zulauf <jzulauf@lunarg.com>
* Author: Tobias Hector <tobias.hector@amd.com>
*/
#include "queue_state.h"
#include "cmd_buffer_state.h"
#include "state_tracker.h"
uint64_t QUEUE_STATE::Submit(CB_SUBMISSION &&submission) {
const uint64_t next_seq = seq + submissions.size() + 1;
bool retire_early = false;
for (auto &cb_node : submission.cbs) {
for (auto *secondary_cmd_buffer : cb_node->linkedCommandBuffers) {
secondary_cmd_buffer->IncrementResources();
}
cb_node->IncrementResources();
// increment use count for all bound objects including secondary cbs
cb_node->BeginUse();
cb_node->Submit(submission.perf_submit_pass);
}
for (auto &wait : submission.wait_semaphores) {
switch (wait.semaphore->scope) {
case kSyncScopeInternal:
if (wait.semaphore->type == VK_SEMAPHORE_TYPE_BINARY) {
wait.semaphore->signaled = false;
}
break;
case kSyncScopeExternalTemporary:
wait.semaphore->scope = kSyncScopeInternal;
break;
default:
break;
}
wait.seq = next_seq;
wait.semaphore->BeginUse();
}
for (auto &signal : submission.signal_semaphores) {
if (signal.semaphore->scope == kSyncScopeInternal) {
signal.semaphore->signaler.queue = this;
signal.semaphore->signaler.seq = next_seq;
if (signal.semaphore->type == VK_SEMAPHORE_TYPE_BINARY) {
signal.semaphore->signaled = true;
}
} else {
retire_early = true;
}
signal.seq = next_seq;
signal.semaphore->BeginUse();
}
if (submission.fence) {
if (submission.fence->scope == kSyncScopeInternal) {
// Mark fence in use
submission.fence->state = FENCE_INFLIGHT;
submission.fence->signaler.queue = this;
submission.fence->signaler.seq = next_seq;
} else {
retire_early = true;
}
submission.fence->BeginUse();
}
submissions.emplace_back(std::move(submission));
return retire_early ? next_seq : 0;
}
void QUEUE_STATE::Retire(uint64_t next_seq) {
layer_data::unordered_map<QUEUE_STATE *, uint64_t> other_queue_seqs;
layer_data::unordered_map<std::shared_ptr<SEMAPHORE_STATE>, uint64_t> timeline_semaphore_counters;
// Roll this queue forward, one submission at a time.
while (seq < next_seq) {
auto &submission = submissions.front();
for (auto &wait : submission.wait_semaphores) {
if (wait.semaphore->type == VK_SEMAPHORE_TYPE_TIMELINE) {
auto &last_counter = timeline_semaphore_counters[wait.semaphore];
last_counter = std::max(last_counter, wait.payload);
wait.semaphore->payload = std::max(wait.semaphore->payload, wait.payload);
} else if (wait.semaphore->signaler.queue) {
auto &last_seq = other_queue_seqs[wait.semaphore->signaler.queue];
last_seq = std::max(last_seq, wait.semaphore->signaler.seq);
} // else this is an external semaphore
wait.semaphore->EndUse();
}
for (auto &signal : submission.signal_semaphores) {
if (signal.semaphore->type == VK_SEMAPHORE_TYPE_TIMELINE && signal.semaphore->payload < signal.payload) {
signal.semaphore->payload = signal.payload;
}
signal.semaphore->EndUse();
}
for (auto cb_node : submission.cbs) {
for (auto *secondary_cmd_buffer : cb_node->linkedCommandBuffers) {
secondary_cmd_buffer->Retire(submission.perf_submit_pass);
}
cb_node->Retire(submission.perf_submit_pass);
cb_node->EndUse();
}
if (submission.fence) {
if (submission.fence->scope == kSyncScopeInternal) {
submission.fence->state = FENCE_RETIRED;
}
submission.fence->EndUse();
}
submissions.pop_front();
seq++;
}
// Roll other queues forward to the highest seq we saw a wait for
for (const auto &qs : other_queue_seqs) {
qs.first->Retire(qs.second);
}
for (const auto &sc : timeline_semaphore_counters) {
sc.first->Retire(sc.second);
}
}
void FENCE_STATE::Retire() {
if (scope == kSyncScopeInternal) {
if (signaler.queue) {
// Fence signaller is a queue -- use this as proof that prior operations on that queue have completed.
signaler.queue->Retire(signaler.seq);
} else {
// Fence signaller is the WSI. We're not tracking what the WSI op actually /was/ in CV yet, but we need to mark
// the fence as retired.
state = FENCE_RETIRED;
}
} else {
state = FENCE_RETIRED;
}
}
void SEMAPHORE_STATE::Retire(uint64_t until_payload) {
if (signaler.queue) {
uint64_t max_seq = 0;
for (const auto &submission : signaler.queue->submissions) {
for (const auto &signal : submission.signal_semaphores) {
if (signal.semaphore.get() == this) {
if (signal.payload <= until_payload && signal.seq > max_seq) {
max_seq = std::max(max_seq, signal.seq);
}
}
}
}
if (max_seq) {
signaler.queue->Retire(max_seq);
}
}
}