refactor(渲染): 优化渲染排序和变换更新机制
- 将渲染命令排序键改为基于图层和深度,替代原有的材质纹理组合 - 引入变换版本号机制,避免冗余的世界变换计算 - 移除命令队列批次执行中的冗余全局UBO绑定 - 跳过仅含变换组件的节点渲染,提升渲染效率
This commit is contained in:
parent
690854698f
commit
2b552347fe
|
|
@ -411,9 +411,8 @@ private:
|
|||
* @brief 执行单个批次
|
||||
* @param batchIndex 批次索引
|
||||
* @param batch 命令批次
|
||||
* @param frameIndex 当前帧索引(用于双缓冲)
|
||||
*/
|
||||
void executeBatch(uint32_t batchIndex, const CommandBatch &batch, uint32_t frameIndex);
|
||||
void executeBatch(uint32_t batchIndex, const CommandBatch &batch);
|
||||
|
||||
/**
|
||||
* @brief 分配材质 UBO 空间(使用 CPU 缓冲区)
|
||||
|
|
|
|||
|
|
@ -102,6 +102,28 @@ struct RenderCommand {
|
|||
Color getColor() const { return drawMesh.color; }
|
||||
};
|
||||
|
||||
constexpr uint32_t SORT_KEY_LAYER_SHIFT = 24;
|
||||
constexpr uint32_t SORT_KEY_DEPTH_SHIFT = 8;
|
||||
constexpr uint32_t SORT_KEY_LAYER_MASK = 0xFF;
|
||||
constexpr uint32_t SORT_KEY_DEPTH_MASK = 0xFFFF;
|
||||
constexpr uint32_t SORT_KEY_FLAGS_MASK = 0xFF;
|
||||
|
||||
inline uint32_t makeSortKey(uint8_t layer, uint16_t depth, uint8_t flags = 0) {
|
||||
return (static_cast<uint32_t>(layer) << SORT_KEY_LAYER_SHIFT) |
|
||||
(static_cast<uint32_t>(depth) << SORT_KEY_DEPTH_SHIFT) |
|
||||
static_cast<uint32_t>(flags);
|
||||
}
|
||||
|
||||
inline uint8_t extractSortLayer(uint32_t sortKey) {
|
||||
return static_cast<uint8_t>((sortKey >> SORT_KEY_LAYER_SHIFT) &
|
||||
SORT_KEY_LAYER_MASK);
|
||||
}
|
||||
|
||||
inline uint16_t extractSortDepth(uint32_t sortKey) {
|
||||
return static_cast<uint16_t>((sortKey >> SORT_KEY_DEPTH_SHIFT) &
|
||||
SORT_KEY_DEPTH_MASK);
|
||||
}
|
||||
|
||||
// 清除标志
|
||||
constexpr uint32_t CLEAR_COLOR_FLAG = 1 << 0;
|
||||
constexpr uint32_t CLEAR_DEPTH_FLAG = 1 << 1;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <scene/component.h>
|
||||
#include <cstdint>
|
||||
#include <types/math/transform.h>
|
||||
#include <types/math/vec2.h>
|
||||
#include <types/math/mat4.h>
|
||||
|
|
@ -150,6 +151,7 @@ public:
|
|||
* @return 是否脏
|
||||
*/
|
||||
bool isDirty() const { return dirty_; }
|
||||
uint64_t getWorldVersion() const;
|
||||
|
||||
private:
|
||||
/**
|
||||
|
|
@ -160,6 +162,10 @@ private:
|
|||
Transform local_;
|
||||
mutable Transform world_;
|
||||
mutable bool dirty_ = true;
|
||||
uint64_t localVersion_ = 1;
|
||||
mutable uint64_t cachedLocalVersion_ = 0;
|
||||
mutable uint64_t cachedParentVersion_ = 0;
|
||||
mutable uint64_t worldVersion_ = 0;
|
||||
Vec2 anchor_ = Vec2(0.5f, 0.5f);
|
||||
Vec2 size_ = Vec2(100.0f, 100.0f);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -366,8 +366,8 @@ void CommandQueue::submitDraw(Ptr<Material> material, Ptr<Mesh> mesh,
|
|||
|
||||
// 构建排序键
|
||||
uint32_t materialId = getMaterialId(material.get());
|
||||
uint16_t depth = static_cast<uint16_t>((sortKey >> 8) & 0xFFFF);
|
||||
uint8_t layer = static_cast<uint8_t>(sortKey & 0xFF);
|
||||
uint16_t depth = extractSortDepth(sortKey);
|
||||
uint8_t layer = extractSortLayer(sortKey);
|
||||
cmd.key = DrawKey::make(materialId, depth, layer);
|
||||
|
||||
// 设置管线
|
||||
|
|
@ -500,8 +500,16 @@ void CommandQueue::execute(uint32_t frameIndex) {
|
|||
|
||||
// 执行批次
|
||||
const auto executeStart = Clock::now();
|
||||
if (uboManager_) {
|
||||
UniformBuffer *globalUBO = uboManager_->getGlobalUBO(frameIndex);
|
||||
if (globalUBO) {
|
||||
commandList_->setUniformBuffer(0, globalUBO->getRHIBuffer());
|
||||
stats_.bufferBinds++;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < batcher_.getBatchCount(); ++i) {
|
||||
executeBatch(i, batcher_.getBatch(i), frameIndex);
|
||||
executeBatch(i, batcher_.getBatch(i));
|
||||
}
|
||||
|
||||
// 提交命令到 GPU
|
||||
|
|
@ -521,8 +529,7 @@ void CommandQueue::execute(uint32_t frameIndex) {
|
|||
std::chrono::duration<float, std::milli>(executeEnd - totalStart).count();
|
||||
}
|
||||
|
||||
void CommandQueue::executeBatch(uint32_t batchIndex, const CommandBatch &batch,
|
||||
uint32_t frameIndex) {
|
||||
void CommandQueue::executeBatch(uint32_t batchIndex, const CommandBatch &batch) {
|
||||
if (!commandList_) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -535,15 +542,6 @@ void CommandQueue::executeBatch(uint32_t batchIndex, const CommandBatch &batch,
|
|||
E2D_WARN("批次没有有效的管线!");
|
||||
}
|
||||
|
||||
// 绑定全局 UBO (binding = 0) - 使用双缓冲
|
||||
if (uboManager_) {
|
||||
UniformBuffer *globalUBO = uboManager_->getGlobalUBO(frameIndex);
|
||||
if (globalUBO) {
|
||||
commandList_->setUniformBuffer(0, globalUBO->getRHIBuffer());
|
||||
stats_.bufferBinds++;
|
||||
}
|
||||
}
|
||||
|
||||
// 绑定纹理
|
||||
if (batch.textureCount > 0) {
|
||||
for (uint32_t i = 0; i < batch.textureCount; ++i) {
|
||||
|
|
|
|||
|
|
@ -29,9 +29,9 @@ void SpriteRenderer::render() {
|
|||
RenderCommand cmd;
|
||||
cmd.type = RenderCommandType::DrawMesh;
|
||||
|
||||
uint32_t materialId = material_.index();
|
||||
uint32_t textureId = texture_.index();
|
||||
cmd.sortKey = (materialId << 16) | (textureId & 0xFFFF);
|
||||
int32 layerTag = owner_->getTag();
|
||||
uint8_t layer = layerTag < 0 ? 0 : static_cast<uint8_t>(layerTag & 0xFF);
|
||||
cmd.sortKey = makeSortKey(layer, 0);
|
||||
|
||||
// 如果没有指定网格,使用默认的四边形网格
|
||||
cmd.drawMesh.mesh = Handle<Mesh>::invalid(); // RendererModule 会使用默认网格
|
||||
|
|
|
|||
|
|
@ -70,14 +70,7 @@ Vec2 TransformComponent::getAnchorOffset() const {
|
|||
|
||||
void TransformComponent::setDirty() {
|
||||
dirty_ = true;
|
||||
// 递归标记所有子节点为脏
|
||||
if (owner_) {
|
||||
for (auto& child : owner_->getChildren()) {
|
||||
if (auto* transform = child->getTransform()) {
|
||||
transform->setDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
++localVersion_;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -87,7 +80,18 @@ void TransformComponent::setDirty() {
|
|||
* 默认1x1的四边形配合64x64的尺寸会正确显示为64x64像素大小。
|
||||
*/
|
||||
void TransformComponent::updateWorldTransform() const {
|
||||
if (!dirty_) return;
|
||||
uint64_t parentVersion = 0;
|
||||
Transform parentWorld;
|
||||
if (owner_ && owner_->getParent()) {
|
||||
if (auto* parentTransform = owner_->getParent()->getTransform()) {
|
||||
parentWorld = parentTransform->getWorldTransform();
|
||||
parentVersion = parentTransform->getWorldVersion();
|
||||
}
|
||||
}
|
||||
if (!dirty_ && cachedLocalVersion_ == localVersion_ &&
|
||||
cachedParentVersion_ == parentVersion) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 计算本地旋转(度数转弧度)
|
||||
float rotRad = local_.rot * glm::pi<float>() / 180.0f;
|
||||
|
|
@ -100,8 +104,6 @@ void TransformComponent::updateWorldTransform() const {
|
|||
// 计算世界变换
|
||||
if (owner_ && owner_->getParent()) {
|
||||
// 有父节点,需要组合变换
|
||||
Transform parentWorld = owner_->getParent()->getWorldTransform();
|
||||
|
||||
// 本地旋转后的锚点偏移
|
||||
float rotatedOffsetX = anchorOffset.x * c - anchorOffset.y * s;
|
||||
float rotatedOffsetY = anchorOffset.x * s + anchorOffset.y * c;
|
||||
|
|
@ -135,6 +137,9 @@ void TransformComponent::updateWorldTransform() const {
|
|||
}
|
||||
|
||||
dirty_ = false;
|
||||
cachedLocalVersion_ = localVersion_;
|
||||
cachedParentVersion_ = parentVersion;
|
||||
++worldVersion_;
|
||||
}
|
||||
|
||||
Transform TransformComponent::getWorldTransform() const {
|
||||
|
|
@ -142,6 +147,11 @@ Transform TransformComponent::getWorldTransform() const {
|
|||
return world_;
|
||||
}
|
||||
|
||||
uint64_t TransformComponent::getWorldVersion() const {
|
||||
updateWorldTransform();
|
||||
return worldVersion_;
|
||||
}
|
||||
|
||||
Mat4 TransformComponent::getWorldMatrix() const {
|
||||
updateWorldTransform();
|
||||
|
||||
|
|
|
|||
|
|
@ -175,14 +175,12 @@ void Node::onExit() {
|
|||
}
|
||||
|
||||
void Node::update(float dt) {
|
||||
// 更新所有组件
|
||||
for (auto& comp : components_) {
|
||||
if (comp->isEnabled()) {
|
||||
if (comp.get() != transform_ && comp->isEnabled()) {
|
||||
comp->update(dt);
|
||||
}
|
||||
}
|
||||
|
||||
// 递归更新子节点
|
||||
for (auto& child : children_) {
|
||||
child->update(dt);
|
||||
}
|
||||
|
|
@ -191,14 +189,16 @@ void Node::update(float dt) {
|
|||
void Node::render() {
|
||||
if (!visible_) return;
|
||||
|
||||
// 渲染所有组件
|
||||
if (children_.empty() && components_.size() == 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& comp : components_) {
|
||||
if (comp->isEnabled()) {
|
||||
if (comp.get() != transform_ && comp->isEnabled()) {
|
||||
comp->render();
|
||||
}
|
||||
}
|
||||
|
||||
// 递归渲染子节点
|
||||
for (auto& child : children_) {
|
||||
child->render();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue