feat(renderer): 添加形状和文本批处理支持

扩展渲染器功能,新增形状批处理(ShapeBatcher)和文本批处理(TextBatcher)支持。重构批处理状态管理,将单一inBatch标志拆分为inSpriteBatch、inShapeBatch和inTextBatch三个独立标志。添加对应的开始/结束批处理方法,并实现相关绘制功能的批处理集成。
This commit is contained in:
ChestnutYueyue 2026-02-20 10:39:41 +08:00
parent 0999644a71
commit 481d4c8f9d
2 changed files with 217 additions and 23 deletions

View File

@ -5,6 +5,8 @@
#include <extra2d/core/module.h>
#include <extra2d/core/types.h>
#include <extra2d/render/batch/sprite_batcher.h>
#include <extra2d/render/batch/shape_batcher.h>
#include <extra2d/render/batch/text_batcher.h>
#include <extra2d/render/camera/camera.h>
#include <extra2d/render/camera/viewport_adapter.h>
#include <extra2d/render/core/render_queue.h>
@ -305,6 +307,16 @@ public:
// 批处理控制
// ========================================================================
/**
* @brief
*/
void beginBatch();
/**
* @brief
*/
void endBatch();
/**
* @brief
*/
@ -315,6 +327,26 @@ public:
*/
void endSpriteBatch();
/**
* @brief
*/
void beginShapeBatch();
/**
* @brief
*/
void endShapeBatch();
/**
* @brief
*/
void beginTextBatch();
/**
* @brief
*/
void endTextBatch();
/**
* @brief
*/
@ -455,6 +487,8 @@ private:
Ptr<rhi::RHIDevice> device_;
UniquePtr<SpriteBatcher> spriteBatcher_;
UniquePtr<ShapeBatcher> shapeBatcher_;
UniquePtr<TextBatcher> textBatcher_;
UniquePtr<RenderQueue> renderQueue_;
ViewportAdapter viewportAdapter_;
@ -472,7 +506,9 @@ private:
uint64_t sortKey_;
int layer_;
rhi::BlendState blendState_;
bool inBatch_;
bool inSpriteBatch_;
bool inShapeBatch_;
bool inTextBatch_;
};
} // namespace extra2d

View File

@ -12,13 +12,13 @@ Renderer::Renderer()
: window_(nullptr), config_(), width_(0), height_(0), initialized_(false),
projectionMatrix_(1.0f), viewMatrix_(1.0f), stats_(),
sortKey_(0), layer_(0), blendState_(rhi::BlendState::alphaBlend()),
inBatch_(false) {}
inSpriteBatch_(false), inShapeBatch_(false), inTextBatch_(false) {}
Renderer::Renderer(const RendererConfig &config)
: window_(nullptr), config_(config), width_(0), height_(0), initialized_(false),
projectionMatrix_(1.0f), viewMatrix_(1.0f), stats_(),
sortKey_(0), layer_(0), blendState_(rhi::BlendState::alphaBlend()),
inBatch_(false) {}
inSpriteBatch_(false), inShapeBatch_(false), inTextBatch_(false) {}
Renderer::~Renderer() { shutdown(); }
@ -49,12 +49,26 @@ bool Renderer::init(IWindow *window, const RendererConfig &config) {
}
spriteBatcher_ = makeUnique<SpriteBatcher>();
SpriteBatcherConfig batcherConfig;
batcherConfig.maxBatchSize = config.maxBatchSize;
SpriteBatcherConfig spriteConfig;
spriteConfig.maxBatchSize = config.maxBatchSize;
if (!spriteBatcher_->init(device_)) {
return false;
}
shapeBatcher_ = makeUnique<ShapeBatcher>();
ShapeBatcherConfig shapeConfig;
shapeConfig.maxBatchSize = config.maxBatchSize / 2;
if (!shapeBatcher_->init(device_)) {
return false;
}
textBatcher_ = makeUnique<TextBatcher>();
TextBatcherConfig textConfig;
textConfig.maxBatchSize = config.maxBatchSize / 2;
if (!textBatcher_->init(device_)) {
return false;
}
renderQueue_ = makeUnique<RenderQueue>();
projectionMatrix_ = glm::ortho(0.0f, static_cast<float>(width_),
@ -78,6 +92,16 @@ void Renderer::shutdown() {
spriteBatcher_.reset();
}
if (shapeBatcher_) {
shapeBatcher_->shutdown();
shapeBatcher_.reset();
}
if (textBatcher_) {
textBatcher_->shutdown();
textBatcher_.reset();
}
if (renderQueue_) {
renderQueue_.reset();
}
@ -118,10 +142,18 @@ void Renderer::endFrame() {
return;
}
if (inBatch_) {
if (inSpriteBatch_) {
endSpriteBatch();
}
if (inShapeBatch_) {
endShapeBatch();
}
if (inTextBatch_) {
endTextBatch();
}
device_->endFrame();
}
@ -201,12 +233,22 @@ void Renderer::drawSprite(Ptr<rhi::RHITexture> texture, const Rect &destRect,
stats_.spriteCount++;
if (!inBatch_) {
if (!inSpriteBatch_) {
beginSpriteBatch();
}
Rect adjustedSrcRect = srcRect;
if (flipX) {
adjustedSrcRect.origin.x += adjustedSrcRect.size.width;
adjustedSrcRect.size.width = -adjustedSrcRect.size.width;
}
if (flipY) {
adjustedSrcRect.origin.y += adjustedSrcRect.size.height;
adjustedSrcRect.size.height = -adjustedSrcRect.size.height;
}
Vec2 anchor(0.5f, 0.5f);
spriteBatcher_->draw(texture, destRect, srcRect, color, rotation, anchor, blendState_);
spriteBatcher_->draw(texture, destRect, adjustedSrcRect, color, rotation, anchor, blendState_);
}
void Renderer::drawSprite(Ptr<rhi::RHITexture> texture,
@ -218,7 +260,7 @@ void Renderer::drawSprite(Ptr<rhi::RHITexture> texture,
stats_.spriteCount++;
if (!inBatch_) {
if (!inSpriteBatch_) {
beginSpriteBatch();
}
@ -264,92 +306,208 @@ Vec2 Renderer::measureText(const std::u32string &text, float fontSize) {
}
void Renderer::drawRect(const Rect &rect, const Color &color, float lineWidth) {
if (!initialized_) {
if (!initialized_ || !shapeBatcher_) {
return;
}
if (!inShapeBatch_) {
beginShapeBatch();
}
shapeBatcher_->drawRect(rect, color, lineWidth);
stats_.shapeCount++;
}
void Renderer::fillRect(const Rect &rect, const Color &color) {
if (!initialized_) {
if (!initialized_ || !shapeBatcher_) {
return;
}
if (!inShapeBatch_) {
beginShapeBatch();
}
shapeBatcher_->drawFilledRect(rect, color);
stats_.shapeCount++;
}
void Renderer::drawCircle(const Vec2 &center, float radius, const Color &color,
float lineWidth, uint32_t segments) {
if (!initialized_) {
if (!initialized_ || !shapeBatcher_) {
return;
}
if (!inShapeBatch_) {
beginShapeBatch();
}
shapeBatcher_->drawCircle(center, radius, color, static_cast<int>(segments), lineWidth);
stats_.shapeCount++;
}
void Renderer::fillCircle(const Vec2 &center, float radius, const Color &color,
uint32_t segments) {
if (!initialized_) {
if (!initialized_ || !shapeBatcher_) {
return;
}
if (!inShapeBatch_) {
beginShapeBatch();
}
shapeBatcher_->drawFilledCircle(center, radius, color, static_cast<int>(segments));
stats_.shapeCount++;
}
void Renderer::drawLine(const Vec2 &start, const Vec2 &end, const Color &color,
float lineWidth) {
if (!initialized_) {
if (!initialized_ || !shapeBatcher_) {
return;
}
if (!inShapeBatch_) {
beginShapeBatch();
}
shapeBatcher_->drawLine(start, end, color, lineWidth);
stats_.shapeCount++;
}
void Renderer::drawPolygon(const Vec2 *points, size_t count, const Color &color,
float lineWidth) {
if (!initialized_ || !points || count < 3) {
if (!initialized_ || !points || count < 3 || !shapeBatcher_) {
return;
}
if (!inShapeBatch_) {
beginShapeBatch();
}
std::vector<Vec2> pointVec(points, points + count);
shapeBatcher_->drawPolygon(pointVec, color, lineWidth);
stats_.shapeCount++;
}
void Renderer::fillPolygon(const Vec2 *points, size_t count,
const Color &color) {
if (!initialized_ || !points || count < 3) {
if (!initialized_ || !points || count < 3 || !shapeBatcher_) {
return;
}
if (!inShapeBatch_) {
beginShapeBatch();
}
std::vector<Vec2> pointVec(points, points + count);
shapeBatcher_->drawFilledPolygon(pointVec, color);
stats_.shapeCount++;
}
void Renderer::beginSpriteBatch() {
if (!initialized_ || !spriteBatcher_ || inBatch_) {
void Renderer::beginBatch() {
if (!initialized_) {
return;
}
inBatch_ = true;
beginSpriteBatch();
beginShapeBatch();
beginTextBatch();
}
void Renderer::endBatch() {
if (!initialized_) {
return;
}
endSpriteBatch();
endShapeBatch();
endTextBatch();
}
void Renderer::beginSpriteBatch() {
if (!initialized_ || !spriteBatcher_ || inSpriteBatch_) {
return;
}
inSpriteBatch_ = true;
spriteBatcher_->begin(projectionMatrix_ * viewMatrix_);
}
void Renderer::endSpriteBatch() {
if (!initialized_ || !spriteBatcher_ || !inBatch_) {
if (!initialized_ || !spriteBatcher_ || !inSpriteBatch_) {
return;
}
spriteBatcher_->end();
inBatch_ = false;
inSpriteBatch_ = false;
stats_.batchCount++;
stats_.drawCalls += spriteBatcher_->getDrawCallCount();
}
void Renderer::flush() {
if (!initialized_ || !spriteBatcher_) {
void Renderer::beginShapeBatch() {
if (!initialized_ || !shapeBatcher_ || inShapeBatch_) {
return;
}
inShapeBatch_ = true;
shapeBatcher_->begin(projectionMatrix_ * viewMatrix_);
}
void Renderer::endShapeBatch() {
if (!initialized_ || !shapeBatcher_ || !inShapeBatch_) {
return;
}
shapeBatcher_->end();
inShapeBatch_ = false;
stats_.batchCount++;
stats_.drawCalls += shapeBatcher_->getDrawCallCount();
}
void Renderer::beginTextBatch() {
if (!initialized_ || !textBatcher_ || inTextBatch_) {
return;
}
inTextBatch_ = true;
textBatcher_->begin(projectionMatrix_ * viewMatrix_);
}
void Renderer::endTextBatch() {
if (!initialized_ || !textBatcher_ || !inTextBatch_) {
return;
}
textBatcher_->end();
inTextBatch_ = false;
stats_.batchCount++;
stats_.drawCalls += textBatcher_->getDrawCallCount();
}
void Renderer::flush() {
if (!initialized_) {
return;
}
if (spriteBatcher_ && inSpriteBatch_) {
spriteBatcher_->end();
spriteBatcher_->begin(projectionMatrix_ * viewMatrix_);
stats_.batchCount++;
stats_.drawCalls += spriteBatcher_->getDrawCallCount();
}
if (shapeBatcher_ && inShapeBatch_) {
shapeBatcher_->end();
shapeBatcher_->begin(projectionMatrix_ * viewMatrix_);
stats_.batchCount++;
stats_.drawCalls += shapeBatcher_->getDrawCallCount();
}
if (textBatcher_ && inTextBatch_) {
textBatcher_->end();
textBatcher_->begin(projectionMatrix_ * viewMatrix_);
stats_.batchCount++;
stats_.drawCalls += textBatcher_->getDrawCallCount();
}
}
void Renderer::setSortKey(uint64_t key) {