graphics: replace command fences with timeline reuse

This commit is contained in:
nmzik
2026-08-26 10:03:43 +02:00
parent 7adade0df5
commit 8072718462
11 changed files with 248 additions and 486 deletions
@@ -6,11 +6,7 @@
#include "graphics/host_gpu/renderer/masterSemaphore.h"
#include "graphics/host_gpu/renderer/render.h"
#include <array>
#include <atomic>
#include <condition_variable>
#include <deque>
#include <memory>
#include <mutex>
#include <queue>
@@ -20,16 +16,6 @@
namespace Libs::Graphics {
struct CommandSlot {
Common::Mutex* pool_mutex = nullptr;
uint32_t id = 0;
vk::CommandBuffer buffer = nullptr;
vk::Fence fence = nullptr;
bool busy = false;
void Reset();
};
class CommandScheduler {
public:
CommandScheduler(RenderContext& context, GraphicContext& graphics);
@@ -41,9 +27,10 @@ public:
void EndRendering();
void Flush();
void Flush(SubmitInfo& submit);
CommandBuffer& FlushAndGetSubmitted();
void FlushAndWait();
void Finish();
void FinishCurrent();
CommandBuffer& BeginCommand();
uint64_t Submit(SubmitInfo submit = {});
// Deferred callbacks can observe an externally owned drain, but cannot initiate shutdown:
// the priority runner cannot join itself.
void Shutdown();
@@ -55,9 +42,9 @@ public:
void DeferPriorityOperation(Common::UniqueFunction<void>&& operation);
[[nodiscard]] static bool InDeferredOperation() noexcept;
[[nodiscard]] bool Active() const noexcept { return m_current >= 0; }
[[nodiscard]] bool Active() const noexcept { return m_registers != nullptr; }
void CheckActive() const;
RenderCommandBuffer& Current() const;
RenderCommandBuffer& Current();
[[nodiscard]] uint64_t CurrentTick() const noexcept { return m_master.CurrentTick(); }
[[nodiscard]] bool IsFree(uint64_t tick);
[[nodiscard]] MasterSemaphore& GetMasterSemaphore() noexcept { return m_master; }
@@ -65,25 +52,25 @@ public:
[[nodiscard]] GraphicContext& Graphics() const noexcept { return m_graphics; }
private:
static constexpr size_t CommandBufferGrowStep = 4;
class CommandPool {
public:
CommandPool() = default;
CommandPool(GraphicContext& graphics, MasterSemaphore& master);
~CommandPool();
KYTY_CLASS_NO_COPY(CommandPool);
CommandSlot* Allocate(GraphicContext& graphics);
vk::CommandBuffer Commit();
private:
void Create(GraphicContext& graphics);
CommandSlot* CreateSlot();
void Destroy();
static constexpr size_t GrowStep = 4;
GraphicContext* m_graphics = nullptr;
Common::Mutex m_mutex;
vk::CommandPool m_pool = nullptr;
std::deque<CommandSlot> m_slots;
size_t Grow();
GraphicContext& m_graphics;
MasterSemaphore& m_master;
vk::CommandPool m_pool = nullptr;
std::vector<vk::CommandBuffer> m_buffers;
std::vector<uint64_t> m_ticks;
size_t m_hint = 0;
};
enum class OperationState { Open, Draining, Closed };
@@ -93,39 +80,28 @@ private:
uint64_t tick = 0;
};
void BindCurrent() const;
CommandBuffer& SubmitCurrent(SubmitInfo& submit);
void BeginNext();
void PopPendingOperations(bool refresh_gpu_tick);
[[nodiscard]] int FindReusableBuffer(uint64_t gpu_tick) const;
[[nodiscard]] size_t GrowCommandBuffers();
void PriorityOperationsThread(std::stop_token stop);
void RunOperation(Common::UniqueFunction<void>&& operation);
[[nodiscard]] CommandSlot* AllocateCommandBuffer();
[[nodiscard]] uint64_t NextSubmitSequence() noexcept;
void BindCurrent();
void BeginNext();
void PopPendingOperations(bool refresh_gpu_tick);
void PriorityOperationsThread(std::stop_token stop);
void RunOperation(Common::UniqueFunction<void>&& operation);
MasterSemaphore m_master;
RenderContext& m_context;
GraphicContext& m_graphics;
CommandPool m_command_pool;
std::vector<std::unique_ptr<RenderCommandBuffer>> m_buffers;
std::vector<uint64_t> m_buffer_ticks;
std::queue<PendingOperation> m_pending_operations;
std::queue<PendingOperation> m_priority_operations;
std::mutex m_operation_mutex;
std::condition_variable m_operation_available;
std::jthread m_priority_thread;
bool m_priority_active = false;
uint64_t m_priority_active_tick = 0;
OperationState m_operation_state = OperationState::Open;
int m_current = -1;
bool m_recording = false;
HW::Context* m_registers = nullptr;
HW::UserConfig* m_user_config = nullptr;
HW::Shader* m_shaders = nullptr;
std::atomic<uint64_t> m_submit_sequence = 0;
friend class CommandBuffer;
MasterSemaphore m_master;
RenderContext& m_context;
GraphicContext& m_graphics;
CommandPool m_command_pool;
RenderCommandBuffer m_command;
std::queue<PendingOperation> m_pending_operations;
std::queue<PendingOperation> m_priority_operations;
std::mutex m_operation_mutex;
std::condition_variable m_operation_available;
std::jthread m_priority_thread;
bool m_priority_active = false;
uint64_t m_priority_active_tick = 0;
OperationState m_operation_state = OperationState::Open;
HW::Context* m_registers = nullptr;
HW::UserConfig* m_user_config = nullptr;
HW::Shader* m_shaders = nullptr;
};
} // namespace Libs::Graphics