From 481d4c8f9db63fa0767ff1f7c87f18353ba21437 Mon Sep 17 00:00:00 2001 From: ChestnutYueyue <952134128@qq.com> Date: Fri, 20 Feb 2026 10:39:41 +0800 Subject: [PATCH] =?UTF-8?q?feat(renderer):=20=E6=B7=BB=E5=8A=A0=E5=BD=A2?= =?UTF-8?q?=E7=8A=B6=E5=92=8C=E6=96=87=E6=9C=AC=E6=89=B9=E5=A4=84=E7=90=86?= =?UTF-8?q?=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 扩展渲染器功能,新增形状批处理(ShapeBatcher)和文本批处理(TextBatcher)支持。重构批处理状态管理,将单一inBatch标志拆分为inSpriteBatch、inShapeBatch和inTextBatch三个独立标志。添加对应的开始/结束批处理方法,并实现相关绘制功能的批处理集成。 --- Extra2D/include/extra2d/render/renderer.h | 38 +++- Extra2D/src/render/renderer.cpp | 202 +++++++++++++++++++--- 2 files changed, 217 insertions(+), 23 deletions(-) diff --git a/Extra2D/include/extra2d/render/renderer.h b/Extra2D/include/extra2d/render/renderer.h index e67e7b6..df2c1d4 100644 --- a/Extra2D/include/extra2d/render/renderer.h +++ b/Extra2D/include/extra2d/render/renderer.h @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include #include #include @@ -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 device_; UniquePtr spriteBatcher_; + UniquePtr shapeBatcher_; + UniquePtr textBatcher_; UniquePtr 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 diff --git a/Extra2D/src/render/renderer.cpp b/Extra2D/src/render/renderer.cpp index c15103e..c6c554a 100644 --- a/Extra2D/src/render/renderer.cpp +++ b/Extra2D/src/render/renderer.cpp @@ -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(); - SpriteBatcherConfig batcherConfig; - batcherConfig.maxBatchSize = config.maxBatchSize; + SpriteBatcherConfig spriteConfig; + spriteConfig.maxBatchSize = config.maxBatchSize; if (!spriteBatcher_->init(device_)) { return false; } + shapeBatcher_ = makeUnique(); + ShapeBatcherConfig shapeConfig; + shapeConfig.maxBatchSize = config.maxBatchSize / 2; + if (!shapeBatcher_->init(device_)) { + return false; + } + + textBatcher_ = makeUnique(); + TextBatcherConfig textConfig; + textConfig.maxBatchSize = config.maxBatchSize / 2; + if (!textBatcher_->init(device_)) { + return false; + } + renderQueue_ = makeUnique(); projectionMatrix_ = glm::ortho(0.0f, static_cast(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 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 texture, @@ -218,7 +260,7 @@ void Renderer::drawSprite(Ptr 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 ¢er, 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(segments), lineWidth); stats_.shapeCount++; } void Renderer::fillCircle(const Vec2 ¢er, float radius, const Color &color, uint32_t segments) { - if (!initialized_) { + if (!initialized_ || !shapeBatcher_) { return; } + if (!inShapeBatch_) { + beginShapeBatch(); + } + + shapeBatcher_->drawFilledCircle(center, radius, color, static_cast(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 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 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) {