Files
KytyPS5/src/graphics/host_gpu/renderer/commandScheduler.h
T
2026-10-10 03:28:02 +02:00

109 lines
4.1 KiB
C++

#ifndef EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_COMMANDSCHEDULER_H_
#define EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_COMMANDSCHEDULER_H_
#include "common/common.h"
#include "common/uniqueFunction.h"
#include "graphics/host_gpu/renderer/dynamicState.h"
#include "graphics/host_gpu/renderer/masterSemaphore.h"
#include "graphics/host_gpu/renderer/render.h"
#include <condition_variable>
#include <mutex>
#include <queue>
#include <thread>
#include <vector>
namespace Libs::Graphics {
class CommandScheduler {
public:
CommandScheduler(RenderContext& context, GraphicContext& graphics);
~CommandScheduler();
KYTY_CLASS_NO_COPY(CommandScheduler);
void Begin(HW::Context& registers, HW::UserConfig& user_config, HW::Shader& shaders);
void BeginRendering(const RenderState& state);
void EndRendering();
void Flush();
void Flush(SubmitInfo& submit);
void FlushAndWait();
void Finish();
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();
void Wait(uint64_t tick);
void PopPendingOperations();
void DrainPriorityOperations();
void WaitPriorityOperations(uint64_t tick);
// Guest-memory completions use the priority queue; normal callbacks maintain GPU resources.
void DeferOperation(Common::UniqueFunction<void>&& operation);
void DeferPriorityOperation(Common::UniqueFunction<void>&& operation);
[[nodiscard]] bool HasPendingPriorityOperations();
[[nodiscard]] static bool InDeferredOperation() noexcept;
[[nodiscard]] bool Active() const noexcept { return m_command.m_registers != nullptr; }
void CheckActive() const;
CommandBuffer& Current();
[[nodiscard]] uint64_t CurrentTick() const noexcept { return m_master.CurrentTick(); }
[[nodiscard]] bool IsFree(uint64_t tick);
[[nodiscard]] MasterSemaphore& GetMasterSemaphore() noexcept { return m_master; }
[[nodiscard]] DynamicState& GetDynamicState() noexcept { return m_dynamic_state; }
[[nodiscard]] RenderContext& Context() const noexcept { return m_context; }
[[nodiscard]] GraphicContext& Graphics() const noexcept { return m_graphics; }
private:
class CommandPool {
public:
CommandPool(GraphicContext& graphics, MasterSemaphore& master);
~CommandPool();
KYTY_CLASS_NO_COPY(CommandPool);
vk::CommandBuffer Commit();
private:
static constexpr size_t GrowStep = 4;
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 };
struct PendingOperation {
Common::UniqueFunction<void> callback;
uint64_t tick = 0;
};
void BeginNext();
void PriorityOperationsThread(std::stop_token stop);
void QueueOperation(Common::UniqueFunction<void>&& operation, bool priority);
void RunOperation(Common::UniqueFunction<void>&& operation);
MasterSemaphore m_master;
RenderContext& m_context;
GraphicContext& m_graphics;
CommandPool m_command_pool;
CommandBuffer m_command;
DynamicState m_dynamic_state;
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;
};
} // namespace Libs::Graphics
#endif // EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_COMMANDSCHEDULER_H_