Extra2D/include/renderer/command_queue.h

347 lines
8.3 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 <types/math/color.h>
#include <types/math/transform.h>
#include <unordered_map>
#include <vector>
namespace extra2d {
// 前向声明
class CommandQueue;
class Material;
class Mesh;
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 大小
// 变换和颜色数据(用于设置 shader uniform
Mat4 modelMatrix; // 模型矩阵
Color color; // 颜色
DrawCommand()
: vertexCount(0), indexCount(0), instanceCount(1), textureCount(0),
materialUBOSize(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
* @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 static_cast<uint32_t>(commands_.size()); }
/**
* @brief
*/
void clear();
private:
std::vector<DrawCommand> commands_;
std::vector<uint32_t> sortedIndices_;
};
/**
* @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 instanceCount
*/
void submitDrawInstanced(Ptr<Material> material, Ptr<Mesh> mesh,
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
*
*
*/
void execute();
/**
* @brief
* @return
*/
uint32_t getCommandCount() const { return sorter_.getCount(); }
/**
* @brief
* @return
*/
RHICommandList* getCommandList() const { return commandList_.get(); }
private:
CommandSorter sorter_;
CommandBatcher batcher_;
RHIContext *context_ = nullptr;
std::unique_ptr<RHICommandList> commandList_;
// 全局 UBO 数据
struct GlobalUBOData {
float viewProjection[16];
float time;
float screenSize[2];
float padding;
} globalUBOData_;
// 材质 UBO 数据缓冲区
std::vector<uint8_t> materialUBOData_;
// 当前材质 ID 计数器
uint32_t nextMaterialId_ = 1;
// 材质到 ID 的映射
std::unordered_map<Material *, uint32_t> materialIds_;
/**
* @brief ID
* @param material
* @return ID
*/
uint32_t getMaterialId(Material *material);
/**
* @brief
* @param batchIndex
* @param batch
*/
void executeBatch(uint32_t batchIndex, const CommandBatch &batch);
};
} // namespace extra2d