#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace extra2d { // ======================================== // CommandSorter 实现 // ======================================== uint32_t CommandSorter::addCommand(const DrawCommand &cmd) { uint32_t index = static_cast(commands_.size()); commands_.push_back(cmd); sortedIndices_.push_back(index); return index; } void CommandSorter::sort() { // 使用稳定排序保持相同键的命令顺序 std::stable_sort(sortedIndices_.begin(), sortedIndices_.end(), [this](uint32_t a, uint32_t b) { return commands_[a].key < commands_[b].key; }); } void CommandSorter::clear() { commands_.clear(); sortedIndices_.clear(); } // ======================================== // CommandBatcher 实现 // ======================================== void CommandBatcher::process(const CommandSorter &sorter) { clear(); sorter_ = &sorter; if (sorter.getCount() == 0) { return; } CommandBatch currentBatch; currentBatch.startIndex = 0; currentBatch.count = 1; const auto &firstCmd = sorter.getCommand(0); currentBatch.pipeline = firstCmd.pipeline; currentBatch.textureCount = firstCmd.textureCount; for (uint32_t i = 0; i < firstCmd.textureCount; ++i) { currentBatch.textures[i] = firstCmd.textures[i]; } // 遍历所有命令,合并兼容的命令 for (uint32_t i = 1; i < sorter.getCount(); ++i) { const auto &cmd = sorter.getCommand(i); if (currentBatch.isCompatibleWith(cmd)) { // 兼容,加入当前批次 currentBatch.count++; } else { // 不兼容,保存当前批次并创建新批次 batches_.push_back(currentBatch); currentBatch.startIndex = i; currentBatch.count = 1; currentBatch.pipeline = cmd.pipeline; currentBatch.textureCount = cmd.textureCount; for (uint32_t j = 0; j < cmd.textureCount; ++j) { currentBatch.textures[j] = cmd.textures[j]; } } } // 保存最后一个批次 batches_.push_back(currentBatch); } const DrawCommand &CommandBatcher::getCommand(uint32_t batchIndex, uint32_t cmdIndex) const { const auto &batch = batches_[batchIndex]; return sorter_->getCommand(batch.startIndex + cmdIndex); } void CommandBatcher::clear() { batches_.clear(); sorter_ = nullptr; } // ======================================== // CommandQueue 实现 // ======================================== CommandQueue::CommandQueue() = default; CommandQueue::~CommandQueue() { shutdown(); } CommandQueue::CommandQueue(CommandQueue &&other) noexcept : sorter_(std::move(other.sorter_)), batcher_(std::move(other.batcher_)), context_(other.context_), commandList_(std::move(other.commandList_)), uboManager_(std::move(other.uboManager_)), globalUBOData_(other.globalUBOData_), materialUBOData_(std::move(other.materialUBOData_)), nextMaterialId_(other.nextMaterialId_), materialIds_(std::move(other.materialIds_)), currentMaterialUBO_(other.currentMaterialUBO_), currentMaterialUBOOffset_(other.currentMaterialUBOOffset_) { other.context_ = nullptr; other.globalUBOData_ = {}; other.nextMaterialId_ = 1; other.currentMaterialUBO_ = nullptr; other.currentMaterialUBOOffset_ = 0; } CommandQueue &CommandQueue::operator=(CommandQueue &&other) noexcept { if (this != &other) { shutdown(); sorter_ = std::move(other.sorter_); batcher_ = std::move(other.batcher_); context_ = other.context_; commandList_ = std::move(other.commandList_); uboManager_ = std::move(other.uboManager_); globalUBOData_ = other.globalUBOData_; materialUBOData_ = std::move(other.materialUBOData_); nextMaterialId_ = other.nextMaterialId_; materialIds_ = std::move(other.materialIds_); currentMaterialUBO_ = other.currentMaterialUBO_; currentMaterialUBOOffset_ = other.currentMaterialUBOOffset_; other.context_ = nullptr; other.globalUBOData_ = {}; other.nextMaterialId_ = 1; other.currentMaterialUBO_ = nullptr; other.currentMaterialUBOOffset_ = 0; } return *this; } bool CommandQueue::initialize() { // 获取 RHI 模块 auto *rhiModule = RHIModule::get(); if (!rhiModule) { E2D_LOG_ERROR("RHIModule not available"); return false; } auto *device = rhiModule->getDevice(); if (!device) { E2D_LOG_ERROR("RHIDevice not available"); return false; } context_ = rhiModule->getContext(); if (!context_) { E2D_LOG_ERROR("RHIContext not available"); return false; } // 创建命令列表 commandList_ = device->createCommandList(); if (!commandList_) { E2D_LOG_ERROR("Failed to create command list"); return false; } // 初始化 UBO 管理器 uboManager_ = std::make_unique(); if (!uboManager_->initialize()) { E2D_LOG_ERROR("Failed to initialize UniformBufferManager"); return false; } // 预分配材质 UBO 数据缓冲区 materialUBOData_.reserve(1024 * 1024); // 1MB E2D_LOG_INFO("CommandQueue initialized"); return true; } void CommandQueue::shutdown() { uboManager_.reset(); commandList_.reset(); context_ = nullptr; materialUBOData_.clear(); E2D_LOG_INFO("CommandQueue shutdown"); } void CommandQueue::beginFrame() { sorter_.clear(); batcher_.clear(); materialIds_.clear(); nextMaterialId_ = 1; materialUBOData_.clear(); // 重置材质 UBO 分配状态 currentMaterialUBO_ = nullptr; currentMaterialUBOOffset_ = 0; // 重置 UBO 管理器的材质 UBO 池 if (uboManager_) { uboManager_->resetMaterialUBOs(); } // 开始录制命令 if (commandList_) { commandList_->begin(); } } void CommandQueue::endFrame() { // 结束录制 if (commandList_) { commandList_->end(); } } uint32_t CommandQueue::getMaterialId(Material *material) { auto it = materialIds_.find(material); if (it != materialIds_.end()) { return it->second; } uint32_t id = nextMaterialId_++; materialIds_[material] = id; return id; } std::pair CommandQueue::allocateMaterialUBO(uint32_t size) { if (!uboManager_ || size == 0) { return {nullptr, 0}; } // 如果当前 UBO 没有足够的空间,获取一个新的 if (currentMaterialUBO_ == nullptr || currentMaterialUBOOffset_ + size > currentMaterialUBO_->getSize()) { currentMaterialUBO_ = uboManager_->acquireMaterialUBO(size); currentMaterialUBOOffset_ = 0; } if (!currentMaterialUBO_) { return {nullptr, 0}; } uint32_t offset = currentMaterialUBOOffset_; currentMaterialUBOOffset_ += size; // 对齐到 16 字节(std140 要求) currentMaterialUBOOffset_ = (currentMaterialUBOOffset_ + 15) & ~15; return {currentMaterialUBO_, offset}; } void CommandQueue::submitDraw(Ptr material, Ptr mesh, const struct Transform &transform, const Color &color) { if (!material || !mesh || !material->getShader()) { return; } DrawCommand cmd; // 构建排序键 uint32_t materialId = getMaterialId(material.get()); cmd.key = DrawKey::make(materialId, 0, 0); // 设置管线 cmd.pipeline = material->getPipeline(); // 设置网格数据 cmd.vertexBuffer = mesh->getVertexBuffer(); cmd.indexBuffer = mesh->getIndexBuffer(); cmd.vertexCount = mesh->getVertexCount(); cmd.indexCount = mesh->getIndexCount(); // 设置变换和颜色 float matrixData[16]; transform.toMatrix(matrixData); cmd.modelMatrix = glm::make_mat4(matrixData); cmd.color = color; // 设置纹理 const auto &textures = material->getTextures(); cmd.textureCount = static_cast(std::min(textures.size(), size_t(8))); for (uint32_t i = 0; i < cmd.textureCount; ++i) { if (textures[i].texture) { cmd.textures[i] = textures[i].texture->getHandle(); } } // 分配材质 UBO 空间并更新数据 uint32_t materialDataSize = material->getDataSize(); if (materialDataSize > 0) { auto [ubo, offset] = allocateMaterialUBO(materialDataSize); if (ubo) { // 复制材质数据到临时缓冲区,以便修改颜色 std::vector uboData(materialDataSize); std::memcpy(uboData.data(), material->getData(), materialDataSize); // 将实例颜色应用到 UBO 数据中的 uColor 参数 auto layout = material->getLayout(); if (layout) { const auto* param = layout->getParam("uColor"); if (param && param->type == MaterialParamType::Color) { std::memcpy(uboData.data() + param->offset, &color.r, sizeof(float) * 4); } } ubo->update(uboData.data(), materialDataSize, offset); cmd.materialUBO = BufferHandle(ubo->getRHIBuffer()); cmd.materialUBOSize = materialDataSize; cmd.materialUBOOffset = offset; } } sorter_.addCommand(cmd); } void CommandQueue::submitDrawInstanced(Ptr material, Ptr mesh, BufferHandle instanceBuffer, uint32_t instanceCount) { if (!material || !mesh || !material->getShader() || instanceCount == 0) { return; } DrawCommand cmd; // 构建排序键 uint32_t materialId = getMaterialId(material.get()); cmd.key = DrawKey::make(materialId, 0, 0); // 设置管线 cmd.pipeline = material->getPipeline(); // 设置网格数据 cmd.vertexBuffer = mesh->getVertexBuffer(); cmd.indexBuffer = mesh->getIndexBuffer(); cmd.vertexCount = mesh->getVertexCount(); cmd.indexCount = mesh->getIndexCount(); cmd.instanceCount = instanceCount; // 设置实例缓冲区 cmd.instanceBuffer = instanceBuffer; cmd.instanceBufferStride = sizeof(InstanceData); // 64 bytes // 设置纹理 const auto &textures = material->getTextures(); cmd.textureCount = static_cast(std::min(textures.size(), size_t(8))); for (uint32_t i = 0; i < cmd.textureCount; ++i) { if (textures[i].texture) { cmd.textures[i] = textures[i].texture->getHandle(); } } // 分配材质 UBO 空间并更新数据 uint32_t materialDataSize = material->getDataSize(); if (materialDataSize > 0) { auto [ubo, offset] = allocateMaterialUBO(materialDataSize); if (ubo) { ubo->update(material->getData(), materialDataSize, offset); cmd.materialUBO = BufferHandle(ubo->getRHIBuffer()); cmd.materialUBOSize = materialDataSize; cmd.materialUBOOffset = offset; } } sorter_.addCommand(cmd); } void CommandQueue::submitClear(const Color &color, uint32_t flags) { // 清除命令直接执行,不加入排序队列 if (!commandList_) { return; } commandList_->clear(static_cast(flags), color, 1.0f, 0); } void CommandQueue::setViewport(int32_t x, int32_t y, int32_t width, int32_t height) { if (!commandList_) { return; } Viewport viewport; viewport.x = static_cast(x); viewport.y = static_cast(y); viewport.width = static_cast(width); viewport.height = static_cast(height); viewport.minDepth = 0.0f; viewport.maxDepth = 1.0f; commandList_->setViewport(viewport); } void CommandQueue::updateGlobalUBO(const Mat4& viewProjection, float deltaTime, uint32_t screenWidth, uint32_t screenHeight) { if (!uboManager_) { E2D_LOG_WARN("CommandQueue::updateGlobalUBO: uboManager is null"); return; } // 填充全局 UBO 数据 std::memcpy(globalUBOData_.viewProjection, glm::value_ptr(viewProjection), sizeof(float) * 16); globalUBOData_.cameraPosition[0] = 0.0f; globalUBOData_.cameraPosition[1] = 0.0f; globalUBOData_.cameraPosition[2] = 0.0f; globalUBOData_.cameraPosition[3] = 1.0f; globalUBOData_.time = 0.0f; // TODO: 传递实际时间 globalUBOData_.deltaTime = deltaTime; globalUBOData_.screenSize[0] = static_cast(screenWidth); globalUBOData_.screenSize[1] = static_cast(screenHeight); // 更新 UBO uboManager_->updateGlobalUBO(&globalUBOData_, sizeof(globalUBOData_)); } void CommandQueue::execute() { if (!commandList_) { E2D_LOG_ERROR("CommandQueue::execute: commandList is null"); return; } // 排序命令 sorter_.sort(); // 批处理 batcher_.process(sorter_); // 执行批次 for (uint32_t i = 0; i < batcher_.getBatchCount(); ++i) { executeBatch(i, batcher_.getBatch(i)); } // 提交命令到 GPU commandList_->submit(); } void CommandQueue::executeBatch(uint32_t batchIndex, const CommandBatch &batch) { if (!commandList_) { return; } // 绑定管线 if (batch.pipeline.isValid()) { commandList_->setPipeline(batch.pipeline.get()); } else { E2D_LOG_WARN("Batch has no valid pipeline!"); } // 绑定全局 UBO (binding = 0) if (uboManager_) { UniformBuffer* globalUBO = uboManager_->getGlobalUBO(); if (globalUBO) { commandList_->setUniformBuffer(0, globalUBO->getRHIBuffer()); } } // 绑定纹理 if (batch.textureCount > 0) { for (uint32_t i = 0; i < batch.textureCount; ++i) { if (batch.textures[i].isValid()) { commandList_->setTexture(i, batch.textures[i].get()); } } } else { // 如果没有纹理,绑定默认的白色纹理 auto* rhiModule = RHIModule::get(); if (rhiModule && rhiModule->getDevice()) { // 使用默认纹理(白色像素) // 注意:这里应该使用 AssetsModule 的默认纹理 // 暂时跳过,因为我们需要访问 AssetsModule } } // 执行批次中的所有命令 for (uint32_t i = 0; i < batch.count; ++i) { const auto &cmd = batcher_.getCommand(batchIndex, i); // 绑定顶点缓冲区 if (cmd.vertexBuffer.isValid()) { commandList_->setVertexBuffer(0, cmd.vertexBuffer.get(), 0); } else { E2D_LOG_WARN("Draw command has no valid vertex buffer!"); } // 绑定实例缓冲区(实例化渲染) if (cmd.isInstanced() && cmd.instanceBuffer.isValid()) { commandList_->setVertexBuffer(1, cmd.instanceBuffer.get(), 0, cmd.instanceBufferStride); } // 绑定索引缓冲区(如果有) if (cmd.isIndexed() && cmd.indexBuffer.isValid()) { commandList_->setIndexBuffer(cmd.indexBuffer.get(), IndexType::UInt16, 0); } // 绑定材质 UBO (binding = 1) if (cmd.materialUBO.isValid()) { commandList_->setUniformBuffer(1, cmd.materialUBO.get(), cmd.materialUBOOffset, cmd.materialUBOSize); } // 设置模型矩阵(仅在非实例化渲染时使用) if (!cmd.isInstanced()) { commandList_->setUniform("uModelMatrix", cmd.modelMatrix); } // 绘制 if (cmd.isInstanced()) { if (cmd.isIndexed()) { commandList_->drawIndexed(cmd.indexCount, 0, 0, cmd.instanceCount, 0); } else { commandList_->draw(cmd.vertexCount, 0, cmd.instanceCount, 0); } } else { if (cmd.isIndexed()) { commandList_->drawIndexed(cmd.indexCount, 0, 0, 1, 0); } else { commandList_->draw(cmd.vertexCount, 0, 1, 0); } } } } } // namespace extra2d