blob: 0acb860d32217deffe9acd90c40a11abb3ad5ccb [file]
/* Copyright (c) 2026 The Khronos Group Inc.
* Copyright (c) 2026 Valve Corporation
* Copyright (c) 2026 LunarG, Inc.
*
* 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.
*/
#pragma once
#include "containers/custom_containers.h"
#include "containers/span.h"
#include "error_message/error_location.h"
#include <vulkan/vulkan.h>
#include <memory>
#include <mutex>
#include <optional>
#include <vector>
namespace vvl {
class DeviceProxy;
class CommandBuffer;
struct QueueSubmission;
// Batch blocked by a wait-before-signal dependency
struct UnresolvedBatch {
UnresolvedBatch(const Location& submit_loc) : submit_loc_capture(submit_loc) {}
LocationCapture submit_loc_capture;
// Command buffers to validate when dependencies are resolved
std::vector<std::shared_ptr<CommandBuffer>> command_buffers;
// Timeline waits that block this batch
std::vector<VkSemaphoreSubmitInfo> unresolved_timeline_waits;
// Semaphores to signal once all waits are resolved
std::vector<VkSemaphoreSubmitInfo> signals;
};
// Tracks submission batches and initiates submit time validation.
// Submit time validation is performed during submit calls such as QueueSubmit and QueuePresent.
// Validation that depends on actual completion of queue operations is not handled by this subsystem.
//
// Batches with no unresolved dependencies are validated immediately.
// Batches with pending timeline waits are stored until a later submit call resolves the wait.
// vkSignalSemaphore also triggers validation if it resolves a pending wait
class SubmitTimeTracker {
public:
SubmitTimeTracker(DeviceProxy& validator) : validator_(validator) {}
void OnCreateTimelineSemaphore(VkSemaphore timeline, uint64_t initial_value);
void OnDestroyTimelineSemaphore(VkSemaphore timeline);
bool ProcessQueueSubmission(VkQueue queue, const QueueSubmission& submission) const;
bool ProcessSignalSemaphore(const VkSemaphoreSignalInfo& signal_info) const;
bool ProcessPresent(const VkPresentInfoKHR& present_info, const Location& present_info_loc) const;
std::optional<uint64_t> GetTimelineValue(VkSemaphore timeline) const;
private:
bool ProcessBatch(std::vector<std::shared_ptr<CommandBuffer>>&& command_buffers,
vvl::span<const VkSemaphoreSubmitInfo> wait_semaphores,
vvl::span<const VkSemaphoreSubmitInfo> signal_semaphores, VkQueue queue, const Location& submit_loc);
bool ProcessSignal(VkSemaphore timeline, uint64_t signal_value);
std::vector<VkSemaphoreSubmitInfo> GetUnresolvedTimelineWaits(vvl::span<const VkSemaphoreSubmitInfo> wait_semaphores);
bool RegisterTimelineSignals(vvl::span<const VkSemaphoreSubmitInfo> signal_semaphores);
bool PropagateTimelineSignals();
bool CanBeResolved(const UnresolvedBatch& batch) const;
bool UpdateTimelineValue(VkSemaphore timeline, uint64_t signal_value);
private:
// Submit time validation and state updates run under this mutex.
// A batch submitted on one queue may be resolved by another due to wait-before-signal.
// Serializing access to this state ensures the resolving queue validates the batch
// immediately, rather than deferring validation until a later submit on the original queue
mutable std::mutex mutex_;
DeviceProxy& validator_;
vvl::unordered_map<VkSemaphore, uint64_t> timeline_signals_;
vvl::unordered_map<VkQueue, std::vector<UnresolvedBatch>> unresolved_batches_;
};
} // namespace vvl