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