Extra2D/include/renderer/command_queue.h

441 lines
12 KiB
C
Raw Normal View History

#pragma once
#include <array>
#include <memory>
#include <renderer/rhi/rhi.h>
#include <renderer/rhi/rhi_command_list.h>
#include <renderer/uniform_buffer.h>
#include <types/math/color.h>
#include <types/math/transform.h>
#include <unordered_map>
#include <vector>
namespace extra2d {
// 前向声明
class CommandQueue;
class Material;
class Mesh;
class UniformBufferManager;
template <typename T> class Ptr;
/**
* @brief
*
* 64
* | ID (32) | (16) | (8) | (8) |
*/
struct DrawKey {
uint64_t value;
DrawKey() : value(0) {}
explicit DrawKey(uint64_t v) : value(v) {}
// 构建排序键
static DrawKey make(uint32_t materialId, uint16_t depth, uint8_t layer,
uint8_t flags = 0) {
DrawKey key;
key.value = (static_cast<uint64_t>(materialId) << 32) |
(static_cast<uint64_t>(depth) << 16) |
(static_cast<uint64_t>(layer) << 8) |
static_cast<uint64_t>(flags);
return key;
}
uint32_t getMaterialId() const { return static_cast<uint32_t>(value >> 32); }
uint16_t getDepth() const {
return static_cast<uint16_t>((value >> 16) & 0xFFFF);
}
uint8_t getLayer() const { return static_cast<uint8_t>((value >> 8) & 0xFF); }
uint8_t getFlags() const { return static_cast<uint8_t>(value & 0xFF); }
bool operator<(const DrawKey &other) const { return value < other.value; }
bool operator>(const DrawKey &other) const { return value > other.value; }
};
/**
* @brief
*
*
*/
struct DrawCommand {
DrawKey key; // 排序键
PipelineHandle pipeline; // 管线状态
BufferHandle vertexBuffer; // 顶点缓冲区
BufferHandle indexBuffer; // 索引缓冲区(可选)
uint32_t vertexCount; // 顶点数量
uint32_t indexCount; // 索引数量
uint32_t instanceCount; // 实例数量1表示非实例化
std::array<TextureHandle, 8> textures; // 纹理数组
uint32_t textureCount; // 纹理数量
BufferHandle materialUBO; // 材质 UBO
uint32_t materialUBOSize; // 材质 UBO 大小
uint32_t materialUBOOffset; // 材质 UBO 在全局缓冲区中的偏移
BufferHandle instanceBuffer; // 实例数据缓冲区(实例化渲染使用)
uint32_t instanceBufferStride; // 实例数据步长
// 变换和颜色数据(用于设置 shader uniform
Mat4 modelMatrix; // 模型矩阵
Color color; // 颜色
DrawCommand()
: vertexCount(0), indexCount(0), instanceCount(1), textureCount(0),
materialUBOSize(0), materialUBOOffset(0), instanceBufferStride(0),
modelMatrix(glm::identity<Mat4>()), color(Color::White) {}
// 检查是否使用索引绘制
bool isIndexed() const { return indexCount > 0; }
// 检查是否实例化绘制
bool isInstanced() const { return instanceCount > 1; }
};
/**
* @brief
*
* 线
*/
struct CommandBatch {
PipelineHandle pipeline; // 共享管线
std::array<TextureHandle, 8> textures; // 共享纹理
uint32_t textureCount;
uint32_t startIndex; // 批次起始命令索引
uint32_t count; // 批次命令数量
CommandBatch() : textureCount(0), startIndex(0), count(0) {}
// 检查是否与命令兼容
bool isCompatibleWith(const DrawCommand &cmd) const {
if (pipeline != cmd.pipeline)
return false;
if (textureCount != cmd.textureCount)
return false;
for (uint32_t i = 0; i < textureCount; ++i) {
if (textures[i] != cmd.textures[i])
return false;
}
return true;
}
};
/**
* @brief
*
*
* 线> >
* 使
*/
class CommandSorter {
public:
/**
* @brief
*/
CommandSorter();
/**
* @brief
*/
~CommandSorter();
// 禁止拷贝
CommandSorter(const CommandSorter&) = delete;
CommandSorter& operator=(const CommandSorter&) = delete;
// 允许移动
CommandSorter(CommandSorter&&) noexcept;
CommandSorter& operator=(CommandSorter&&) noexcept;
/**
* @brief
* @param cmd
* @return
*/
uint32_t addCommand(const DrawCommand &cmd);
/**
* @brief
*/
void sort();
/**
* @brief
* @param index
* @return
*/
const DrawCommand &getCommand(uint32_t index) const {
return commands_[sortedIndices_[index]];
}
/**
* @brief
* @return
*/
uint32_t getCount() const { return commandCount_; }
/**
* @brief
*/
void clear();
/**
* @brief
* @param capacity
*/
void reserve(uint32_t capacity);
private:
std::vector<DrawCommand> commands_; // 命令缓冲区(复用)
std::vector<uint32_t> sortedIndices_; // 排序索引缓冲区(复用)
uint32_t commandCount_ = 0; // 当前命令数量
static constexpr uint32_t INITIAL_CAPACITY = 1024; // 初始容量
};
/**
* @brief
*
*
*
*/
class CommandBatcher {
public:
/**
* @brief
* @param sorter
*/
void process(const CommandSorter &sorter);
/**
* @brief
* @return
*/
uint32_t getBatchCount() const {
return static_cast<uint32_t>(batches_.size());
}
/**
* @brief
* @param index
* @return
*/
const CommandBatch &getBatch(uint32_t index) const { return batches_[index]; }
/**
* @brief
* @param batchIndex
* @param cmdIndex
* @return
*/
const DrawCommand &getCommand(uint32_t batchIndex, uint32_t cmdIndex) const;
/**
* @brief
*/
void clear();
private:
std::vector<CommandBatch> batches_;
const CommandSorter *sorter_ = nullptr;
};
/**
* @brief
*
*
*
*/
class CommandQueue {
public:
/**
* @brief
*/
CommandQueue();
/**
* @brief
*/
~CommandQueue();
// 禁止拷贝
CommandQueue(const CommandQueue&) = delete;
CommandQueue& operator=(const CommandQueue&) = delete;
// 允许移动
CommandQueue(CommandQueue&&) noexcept;
CommandQueue& operator=(CommandQueue&&) noexcept;
/**
* @brief
* @return
*/
bool initialize();
/**
* @brief
*/
void shutdown();
/**
* @brief
*/
void beginFrame();
/**
* @brief
*/
void endFrame();
/**
* @brief
* @param material
* @param mesh
* @param transform
* @param color
*/
void submitDraw(Ptr<Material> material, Ptr<Mesh> mesh,
const struct Transform &transform, const Color &color);
/**
* @brief
* @param material
* @param mesh
* @param instanceBuffer
* @param instanceCount
*/
void submitDrawInstanced(Ptr<Material> material, Ptr<Mesh> mesh,
BufferHandle instanceBuffer, uint32_t instanceCount);
/**
* @brief
* @param color
* @param flags
*/
void submitClear(const Color &color, uint32_t flags);
/**
* @brief
* @param x X
* @param y Y
* @param width
* @param height
*/
void setViewport(int32_t x, int32_t y, int32_t width, int32_t height);
/**
* @brief
*
*
* @param frameIndex
*/
void execute(uint32_t frameIndex);
/**
* @brief UBO
* @param viewProjection
* @param deltaTime
* @param screenWidth
* @param screenHeight
* @param frameIndex
*/
void updateGlobalUBO(const Mat4& viewProjection, float deltaTime,
uint32_t screenWidth, uint32_t screenHeight, uint32_t frameIndex);
/**
* @brief
* @return
*/
uint32_t getCommandCount() const { return sorter_.getCount(); }
/**
* @brief
* @return
*/
RHICommandList* getCommandList() const { return commandList_.get(); }
/**
* @brief
* @return
*/
const RenderStats& getStats() const { return stats_; }
/**
* @brief
*/
void resetStats() { stats_ = {}; }
private:
CommandSorter sorter_;
CommandBatcher batcher_;
RHIContext *context_ = nullptr;
std::unique_ptr<RHICommandList> commandList_;
// UBO 管理器
std::unique_ptr<UniformBufferManager> uboManager_;
// 渲染统计
RenderStats stats_;
// 全局 UBO 数据 - 必须与着色器中的 std140 布局完全匹配
// layout(std140, binding = 0) uniform GlobalUBO {
// mat4 uViewProjection; // 64 bytes, offset 0
// vec4 uCameraPosition; // 16 bytes, offset 64
// float uTime; // 4 bytes, offset 80
// float uDeltaTime; // 4 bytes, offset 84
// vec2 uScreenSize; // 8 bytes, offset 88
// }; // 总大小: 96 bytes (std140 对齐)
struct alignas(16) GlobalUBOData {
float viewProjection[16]; // 64 bytes, offset 0
float cameraPosition[4]; // 16 bytes, offset 64
float time; // 4 bytes, offset 80
float deltaTime; // 4 bytes, offset 84
float screenSize[2]; // 8 bytes, offset 88
} globalUBOData_;
// 材质 UBO 数据缓冲区
std::vector<uint8_t> materialUBOData_;
// 当前材质 ID 计数器
uint32_t nextMaterialId_ = 1;
// 材质到 ID 的映射
std::unordered_map<Material *, uint32_t> materialIds_;
// 当前材质 UBO 缓冲区
UniformBuffer* currentMaterialUBO_ = nullptr;
uint32_t materialUBOBufferOffset_ = 0;
/**
* @brief ID
* @param material
* @return ID
*/
uint32_t getMaterialId(Material *material);
/**
* @brief
* @param batchIndex
* @param batch
* @param frameIndex
*/
void executeBatch(uint32_t batchIndex, const CommandBatch &batch, uint32_t frameIndex);
/**
* @brief UBO 使 CPU
* @param size
* @return UBO nullptr 使 CPU
*/
std::pair<UniformBuffer*, uint32_t> allocateMaterialUBO(uint32_t size);
/**
* @brief UBO CPU GPU
*/
void flushMaterialUBOToGPU();
/**
* @brief UBO
* @return UBO
*/
UniformBuffer* getCurrentMaterialUBO() const;
};
} // namespace extra2d