This commit is contained in:
lujun
2023-02-06 22:06:27 +08:00
parent f9c85e9b81
commit 934207d732
39 changed files with 3135 additions and 3 deletions

View File

@@ -0,0 +1,29 @@
string(REPLACE "/" "\\" CMD_COCOS_X_PATH "${COCOS_X_PATH}")
string(REPLACE "/" "\\" CMD_CMAKE_CURRENT_LIST_DIR "${CMAKE_CURRENT_LIST_DIR}")
# 引擎编译添加源文件替换依赖目标
add_custom_command(
OUTPUT ${CMAKE_CURRENT_LIST_DIR}/ENGINE_REPLACE.txt
COMMAND copy /y "\"${CMD_CMAKE_CURRENT_LIST_DIR}\\replace\\Batcher2d.h\"" "\"${CMD_COCOS_X_PATH}\\cocos\\2d\\renderer\\Batcher2d.h\""
COMMAND copy /y "\"${CMD_CMAKE_CURRENT_LIST_DIR}\\replace\\Batcher2d.cpp\"" "\"${CMD_COCOS_X_PATH}\\cocos\\2d\\renderer\\Batcher2d.cpp\""
COMMAND copy /y "\"${CMD_CMAKE_CURRENT_LIST_DIR}\\replace\\RenderEntity.h\"" "\"${CMD_COCOS_X_PATH}\\cocos\\2d\\renderer\\RenderEntity.h\""
COMMAND copy /y "\"${CMD_CMAKE_CURRENT_LIST_DIR}\\replace\\RenderEntity.cpp\"" "\"${CMD_COCOS_X_PATH}\\cocos\\2d\\renderer\\RenderEntity.cpp\""
COMMAND echo "ENGINE_REPLACE" >> "${CMD_CMAKE_CURRENT_LIST_DIR}\\ENGINE_REPLACE.txt"
COMMAND echo "LCC_UI_SORTING_GROUP pre"
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
)
add_custom_target(LCC_UI_SORTING_GROUP_ENGINE_REPLACE DEPENDS ${CMAKE_CURRENT_LIST_DIR}/ENGINE_REPLACE.txt)
add_dependencies(${ENGINE_NAME} LCC_UI_SORTING_GROUP_ENGINE_REPLACE)
# 引擎编译恢复源文件
add_custom_command(TARGET ${ENGINE_NAME}
POST_BUILD
COMMAND copy /y "\"${CMD_CMAKE_CURRENT_LIST_DIR}\\backup\\Batcher2d.h\"" "\"${CMD_COCOS_X_PATH}\\cocos\\2d\\renderer\\Batcher2d.h\""
COMMAND copy /y "\"${CMD_CMAKE_CURRENT_LIST_DIR}\\backup\\Batcher2d.cpp\"" "\"${CMD_COCOS_X_PATH}\\cocos\\2d\\renderer\\Batcher2d.cpp\""
COMMAND copy /y "\"${CMD_CMAKE_CURRENT_LIST_DIR}\\backup\\RenderEntity.h\"" "\"${CMD_COCOS_X_PATH}\\cocos\\2d\\renderer\\RenderEntity.h\""
COMMAND copy /y "\"${CMD_CMAKE_CURRENT_LIST_DIR}\\backup\\RenderEntity.cpp\"" "\"${CMD_COCOS_X_PATH}\\cocos\\2d\\renderer\\RenderEntity.cpp\""
COMMAND del "${CMD_CMAKE_CURRENT_LIST_DIR}\\ENGINE_REPLACE.txt"
COMMAND echo "LCC_UI_SORTING_GROUP post"
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
)

View File

@@ -0,0 +1,609 @@
/****************************************************************************
Copyright (c) 2019-2021 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "2d/renderer/Batcher2d.h"
#include "application/ApplicationManager.h"
#include "base/TypeDef.h"
#include "core/Root.h"
#include "editor-support/MiddlewareManager.h"
#include "renderer/pipeline/Define.h"
#include "scene/Pass.h"
namespace cc {
Batcher2d::Batcher2d() : Batcher2d(nullptr) {
}
Batcher2d::Batcher2d(Root* root)
: _drawBatchPool([]() { return ccnew scene::DrawBatch2D(); }, [](auto* obj) { delete obj; }, 10U) {
if (root == nullptr) {
root = Root::getInstance();
}
_root = root;
_device = _root->getDevice();
_stencilManager = StencilManager::getInstance();
}
Batcher2d::~Batcher2d() { // NOLINT
_drawBatchPool.destroy();
for (auto iter : _descriptorSetCache) {
delete iter.second;
}
for (auto* drawBatch : _batches) {
delete drawBatch;
}
_attributes.clear();
if(_maskClearModel != nullptr) {
Root::getInstance()->destroyModel(_maskClearModel);
_maskClearModel = nullptr;
}
if (_maskModelMesh != nullptr) {
_maskModelMesh->destroy();
_maskModelMesh = nullptr;
}
_maskClearMtl = nullptr;
_maskAttributes.clear();
}
void Batcher2d::syncMeshBuffersToNative(uint16_t accId, ccstd::vector<UIMeshBuffer*>&& buffers) {
_meshBuffersMap[accId] = std::move(buffers);
}
UIMeshBuffer* Batcher2d::getMeshBuffer(uint16_t accId, uint16_t bufferId) { // NOLINT(bugprone-easily-swappable-parameters)
const auto& map = _meshBuffersMap[accId];
return map[bufferId];
}
gfx::Device* Batcher2d::getDevice() {
if (_device == nullptr) {
_device = Root::getInstance()->getDevice();
}
return _device;
}
void Batcher2d::updateDescriptorSet() {
}
void Batcher2d::syncRootNodesToNative(ccstd::vector<Node*>&& rootNodes) {
_rootNodeArr = std::move(rootNodes);
}
void Batcher2d::fillBuffersAndMergeBatches() {
for (auto* rootNode : _rootNodeArr) {
walk(rootNode, 1);
generateBatch(_currEntity, _currDrawInfo);
}
}
void Batcher2d::walk(Node* node, float parentOpacity) { // NOLINT(misc-no-recursion)
if (!node->isActiveInHierarchy()) {
return;
}
bool breakWalk = false;
auto* entity = static_cast<RenderEntity*>(node->getUserData());
if (entity) {
if (entity->getColorDirty()) {
float localOpacity = entity->getLocalOpacity();
float localColorAlpha = entity->getColorAlpha();
entity->setOpacity(parentOpacity * localOpacity * localColorAlpha);
entity->setColorDirty(false);
entity->setVBColorDirty(true);
}
if (entity->isEnabled()) {
uint32_t size = entity->getRenderDrawInfosSize();
for (uint32_t i = 0; i < size; i++) {
auto* drawInfo = entity->getRenderDrawInfoAt(i);
handleDrawInfo(entity, drawInfo, node);
}
entity->setVBColorDirty(false);
}
if (entity->getRenderEntityType() == RenderEntityType::CROSSED) {
breakWalk = true;
}
}
if (!breakWalk) {
const auto& children = node->getChildren();
float thisOpacity = entity ? entity->getOpacity() : parentOpacity;
for (const auto& child : children) {
// we should find parent opacity recursively upwards if it doesn't have an entity.
walk(child, thisOpacity);
}
}
// post assembler
if (_stencilManager->getMaskStackSize() > 0 && entity && entity->isEnabled()) {
handlePostRender(entity);
}
}
void Batcher2d::handlePostRender(RenderEntity* entity) {
bool isMask = entity->getIsMask();
if (isMask) {
generateBatch(_currEntity, _currDrawInfo);
resetRenderStates();
_stencilManager->exitMask();
}
}
CC_FORCE_INLINE void Batcher2d::handleComponentDraw(RenderEntity* entity, RenderDrawInfo* drawInfo, Node* node) {
ccstd::hash_t dataHash = drawInfo->getDataHash();
if (drawInfo->getIsMeshBuffer()) {
dataHash = 0;
}
// may slow
bool isMask = entity->getIsMask();
if (isMask) {
// Mask subComp
insertMaskBatch(entity);
} else {
entity->setEnumStencilStage(_stencilManager->getStencilStage());
}
auto tempStage = static_cast<StencilStage>(entity->getStencilStage());
if (_currHash != dataHash || dataHash == 0 || _currMaterial != drawInfo->getMaterial() || _currStencilStage != tempStage) {
// Generate a batch if not batching
generateBatch(_currEntity, _currDrawInfo);
if (!drawInfo->getIsMeshBuffer()) {
UIMeshBuffer* buffer = drawInfo->getMeshBuffer();
if (_currMeshBuffer != buffer) {
_currMeshBuffer = buffer;
_indexStart = _currMeshBuffer->getIndexOffset();
}
}
_currHash = dataHash;
_currMaterial = drawInfo->getMaterial();
_currStencilStage = tempStage;
_currLayer = entity->getNode()->getLayer();
_currEntity = entity;
_currDrawInfo = drawInfo;
_currTexture = drawInfo->getTexture();
_currSampler = drawInfo->getSampler();
if (_currSampler == nullptr) {
_currSamplerHash = 0;
} else {
_currSamplerHash = _currSampler->getHash();
}
}
if (!drawInfo->getIsMeshBuffer()) {
if (node->getChangedFlags() || drawInfo->getVertDirty()) {
fillVertexBuffers(entity, drawInfo);
drawInfo->setVertDirty(false);
}
if (entity->getVBColorDirty()) {
fillColors(entity, drawInfo);
}
fillIndexBuffers(drawInfo);
}
if (isMask) {
_stencilManager->enableMask();
}
}
CC_FORCE_INLINE void Batcher2d::handleModelDraw(RenderEntity* entity, RenderDrawInfo* drawInfo) {
generateBatch(_currEntity, _currDrawInfo);
resetRenderStates();
// stencil stage
gfx::DepthStencilState* depthStencil = nullptr;
ccstd::hash_t dssHash = 0;
Material* renderMat = drawInfo->getMaterial();
bool isMask = entity->getIsMask();
if (isMask) {
//Mask Comp
insertMaskBatch(entity);
} else {
entity->setEnumStencilStage(_stencilManager->getStencilStage());
}
StencilStage entityStage = entity->getEnumStencilStage();
depthStencil = _stencilManager->getDepthStencilState(entityStage, renderMat);
dssHash = _stencilManager->getStencilHash(entityStage);
// Model
auto* model = drawInfo->getModel();
if (model == nullptr) return;
auto stamp = CC_CURRENT_ENGINE()->getTotalFrames();
model->updateTransform(stamp);
model->updateUBOs(stamp);
const auto& subModelList = model->getSubModels();
for (const auto& submodel : subModelList) {
auto* curdrawBatch = _drawBatchPool.alloc();
curdrawBatch->setVisFlags(entity->getNode()->getLayer());
curdrawBatch->setModel(model);
curdrawBatch->setInputAssembler(submodel->getInputAssembler());
curdrawBatch->setDescriptorSet(submodel->getDescriptorSet());
curdrawBatch->fillPass(renderMat, depthStencil, dssHash, &(submodel->getPatches()));
_batches.push_back(curdrawBatch);
}
if(isMask) {
_stencilManager->enableMask();
}
}
CC_FORCE_INLINE void Batcher2d::handleMiddlewareDraw(RenderEntity* entity, RenderDrawInfo* drawInfo) {
auto layer = entity->getNode()->getLayer();
Material* material = drawInfo->getMaterial();
auto* texture = drawInfo->getTexture();
auto* sampler = drawInfo->getSampler();
auto* meshBuffer = drawInfo->getMeshBuffer();
// check for merge draw
auto enableBatch = !entity->getUseLocal();
if (enableBatch && _currTexture == texture && _currMeshBuffer == meshBuffer
&& !_currEntity->getUseLocal()
&& material->getHash() == _currMaterial->getHash()
&& drawInfo->getIndexOffset() == _currDrawInfo->getIndexOffset() + _currDrawInfo->getIbCount()
&& layer == _currLayer) {
auto ibCount = _currDrawInfo->getIbCount();
_currDrawInfo->setIbCount(ibCount + drawInfo->getIbCount());
} else {
generateBatch(_currEntity, _currDrawInfo);
_currLayer = layer;
_currMaterial = material;
_currTexture = texture;
_currMeshBuffer = meshBuffer;
_currEntity = entity;
_currDrawInfo = drawInfo;
_currHash = 0;
}
}
CC_FORCE_INLINE void Batcher2d::handleSubNode(RenderEntity* entity, RenderDrawInfo* drawInfo) { // NOLINT
if (drawInfo->getSubNode()) {
walk(drawInfo->getSubNode(), entity->getOpacity());
}
}
CC_FORCE_INLINE void Batcher2d::handleDrawInfo(RenderEntity* entity, RenderDrawInfo* drawInfo, Node* node) { //NOLINT(misc-no-recursion)
CC_ASSERT(entity);
CC_ASSERT(drawInfo);
RenderDrawInfoType drawInfoType = drawInfo->getEnumDrawInfoType();
switch (drawInfoType) {
case RenderDrawInfoType::COMP:
handleComponentDraw(entity, drawInfo, node);
break;
case RenderDrawInfoType::MODEL:
handleModelDraw(entity, drawInfo);
break;
case RenderDrawInfoType::MIDDLEWARE:
handleMiddlewareDraw(entity, drawInfo);
break;
case RenderDrawInfoType::SUB_NODE:
handleSubNode(entity, drawInfo);
break;
default:
break;
}
}
void Batcher2d::generateBatch(RenderEntity* entity, RenderDrawInfo* drawInfo) {
if (drawInfo == nullptr) {
return;
}
if (drawInfo->getEnumDrawInfoType() == RenderDrawInfoType::MIDDLEWARE) {
generateBatchForMiddleware(entity, drawInfo);
return;
}
if (_currMaterial == nullptr) {
return;
}
gfx::InputAssembler* ia = nullptr;
if (drawInfo->getIsMeshBuffer()) {
// Todo MeshBuffer RenderData
ia = drawInfo->requestIA(getDevice());
_meshRenderDrawInfo.emplace_back(drawInfo);
} else {
UIMeshBuffer* currMeshBuffer = drawInfo->getMeshBuffer();
currMeshBuffer->setDirty(true);
ia = currMeshBuffer->requireFreeIA(getDevice());
uint32_t indexCount = currMeshBuffer->getIndexOffset() - _indexStart;
if (ia == nullptr) {
return;
}
ia->setFirstIndex(_indexStart);
ia->setIndexCount(indexCount);
_indexStart = currMeshBuffer->getIndexOffset();
}
_currMeshBuffer = nullptr;
// stencilStage
gfx::DepthStencilState* depthStencil = nullptr;
ccstd::hash_t dssHash = 0;
StencilStage entityStage = entity->getEnumStencilStage();
depthStencil = _stencilManager->getDepthStencilState(entityStage, _currMaterial);
dssHash = _stencilManager->getStencilHash(entityStage);
auto* curdrawBatch = _drawBatchPool.alloc();
curdrawBatch->setVisFlags(_currLayer);
curdrawBatch->setInputAssembler(ia);
curdrawBatch->fillPass(_currMaterial, depthStencil, dssHash);
const auto& pass = curdrawBatch->getPasses().at(0);
if (entity->getUseLocal()) {
drawInfo->updateLocalDescriptorSet(entity->getRenderTransform(), pass->getLocalSetLayout());
curdrawBatch->setDescriptorSet(drawInfo->getLocalDes());
} else {
curdrawBatch->setDescriptorSet(getDescriptorSet(_currTexture, _currSampler, pass->getLocalSetLayout()));
}
_batches.push_back(curdrawBatch);
}
void Batcher2d::generateBatchForMiddleware(RenderEntity* entity, RenderDrawInfo* drawInfo) {
auto layer = entity->getNode()->getLayer();
auto* material = drawInfo->getMaterial();
auto* texture = drawInfo->getTexture();
auto* sampler = drawInfo->getSampler();
auto* meshBuffer = drawInfo->getMeshBuffer();
//set meshbuffer offset
auto indexOffset = drawInfo->getIndexOffset();
auto indexCount = drawInfo->getIbCount();
indexOffset += indexCount;
if (meshBuffer->getIndexOffset() < indexOffset) {
meshBuffer->setIndexOffset(indexOffset);
}
meshBuffer->setDirty(true);
gfx::InputAssembler* ia = meshBuffer->requireFreeIA(getDevice());
ia->setFirstIndex(drawInfo->getIndexOffset());
ia->setIndexCount(drawInfo->getIbCount());
// stencilstage
auto stencilStage = _stencilManager->getStencilStage();
gfx::DepthStencilState* depthStencil = _stencilManager->getDepthStencilState(stencilStage, material);
ccstd::hash_t dssHash = _stencilManager->getStencilHash(stencilStage);
auto* curdrawBatch = _drawBatchPool.alloc();
curdrawBatch->setVisFlags(_currLayer);
curdrawBatch->setInputAssembler(ia);
curdrawBatch->fillPass(material, depthStencil, dssHash);
const auto& pass = curdrawBatch->getPasses().at(0);
if (entity->getUseLocal()) {
drawInfo->updateLocalDescriptorSet(entity->getNode(), pass->getLocalSetLayout());
curdrawBatch->setDescriptorSet(drawInfo->getLocalDes());
} else {
curdrawBatch->setDescriptorSet(getDescriptorSet(texture, sampler, pass->getLocalSetLayout()));
}
_batches.push_back(curdrawBatch);
// make sure next generateBatch return.
resetRenderStates();
_currMeshBuffer = nullptr;
}
void Batcher2d::resetRenderStates() {
_currMaterial = nullptr;
_currTexture = nullptr;
_currSampler = nullptr;
_currSamplerHash = 0;
_currLayer = 0;
_currEntity = nullptr;
_currDrawInfo = nullptr;
}
gfx::DescriptorSet* Batcher2d::getDescriptorSet(gfx::Texture* texture, gfx::Sampler* sampler, gfx::DescriptorSetLayout* dsLayout) {
ccstd::hash_t hash = 2;
size_t textureHash;
if (texture != nullptr) {
textureHash = boost::hash_value(texture);
ccstd::hash_combine(hash, textureHash);
}
if (sampler != nullptr) {
ccstd::hash_combine(hash, sampler->getHash());
}
auto iter = _descriptorSetCache.find(hash);
if (iter != _descriptorSetCache.end()) {
if (texture != nullptr && sampler != nullptr) {
iter->second->bindTexture(static_cast<uint32_t>(pipeline::ModelLocalBindings::SAMPLER_SPRITE), texture);
iter->second->bindSampler(static_cast<uint32_t>(pipeline::ModelLocalBindings::SAMPLER_SPRITE), sampler);
}
iter->second->forceUpdate();
return iter->second;
}
_dsInfo.layout = dsLayout;
auto* ds = getDevice()->createDescriptorSet(_dsInfo);
if (texture != nullptr && sampler != nullptr) {
ds->bindTexture(static_cast<uint32_t>(pipeline::ModelLocalBindings::SAMPLER_SPRITE), texture);
ds->bindSampler(static_cast<uint32_t>(pipeline::ModelLocalBindings::SAMPLER_SPRITE), sampler);
}
ds->update();
_descriptorSetCache.emplace(hash, ds);
return ds;
}
void Batcher2d::releaseDescriptorSetCache(gfx::Texture* texture, gfx::Sampler* sampler) {
ccstd::hash_t hash = 2;
size_t textureHash;
if (texture != nullptr) {
textureHash = boost::hash_value(texture);
ccstd::hash_combine(hash, textureHash);
}
if (sampler != nullptr) {
ccstd::hash_combine(hash, sampler->getHash());
}
auto iter = _descriptorSetCache.find(hash);
if (iter != _descriptorSetCache.end()) {
delete iter->second;
_descriptorSetCache.erase(hash);
}
}
bool Batcher2d::initialize() {
_isInit = true;
return _isInit;
}
void Batcher2d::update() {
fillBuffersAndMergeBatches();
resetRenderStates();
for (const auto& scene : Root::getInstance()->getScenes()) {
for (auto* batch : _batches) {
scene->addBatch(batch);
}
}
}
void Batcher2d::uploadBuffers() {
if (_batches.empty()) {
return;
}
for (auto& meshRenderData : _meshRenderDrawInfo) {
meshRenderData->uploadBuffers();
}
for (auto& map : _meshBuffersMap) {
for (auto& buffer : map.second) {
buffer->uploadBuffers();
buffer->reset();
}
}
updateDescriptorSet();
}
void Batcher2d::reset() {
for (auto& batch : _batches) {
batch->clear();
_drawBatchPool.free(batch);
}
_batches.clear();
for (auto& meshRenderData : _meshRenderDrawInfo) {
meshRenderData->resetMeshIA();
}
_meshRenderDrawInfo.clear();
// meshDataArray
for (auto& map : _meshBuffersMap) {
for (auto& buffer : map.second) {
if (buffer) {
buffer->resetIA();
}
}
}
//meshBuffer cannot clear because it is not transported at every frame.
_currMeshBuffer = nullptr;
_indexStart = 0;
_currHash = 0;
_currLayer = 0;
_currMaterial = nullptr;
_currTexture = nullptr;
_currSampler = nullptr;
// stencilManager
}
void Batcher2d::insertMaskBatch(RenderEntity* entity){
generateBatch(_currEntity, _currDrawInfo);
resetRenderStates();
createClearModel();
_maskClearModel->setNode(entity->getNode());
_maskClearModel->setTransform(entity->getNode());
_stencilManager->pushMask();
auto stage = _stencilManager->clear(entity);
gfx::DepthStencilState* depthStencil = nullptr;
ccstd::hash_t dssHash = 0;
if(_maskClearMtl != nullptr){
depthStencil = _stencilManager->getDepthStencilState(stage, _maskClearMtl);
dssHash = _stencilManager->getStencilHash(stage);
}
// Model
if (_maskClearModel == nullptr) return;
auto stamp = CC_CURRENT_ENGINE()->getTotalFrames();
_maskClearModel->updateTransform(stamp);
_maskClearModel->updateUBOs(stamp);
const auto& subModelList = _maskClearModel->getSubModels();
for (const auto& submodel : subModelList) {
auto* curdrawBatch = _drawBatchPool.alloc();
curdrawBatch->setVisFlags(entity->getNode()->getLayer());
curdrawBatch->setModel(_maskClearModel);
curdrawBatch->setInputAssembler(submodel->getInputAssembler());
curdrawBatch->setDescriptorSet(submodel->getDescriptorSet());
curdrawBatch->fillPass(_maskClearMtl, depthStencil, dssHash, &(submodel->getPatches()));
_batches.push_back(curdrawBatch);
}
_stencilManager->enterLevel(entity);
}
void Batcher2d::createClearModel() {
if (_maskClearModel == nullptr) {
_maskClearMtl = BuiltinResMgr::getInstance()->get<Material>(ccstd::string("default-clear-stencil"));
_maskClearModel = Root::getInstance()->createModel<scene::Model>();
uint32_t stride = 12;// vfmt
auto* vertexBuffer = _device->createBuffer({
gfx::BufferUsageBit::VERTEX | gfx::BufferUsageBit::TRANSFER_DST,
gfx::MemoryUsageBit::DEVICE,
4 * stride,
stride,
});
const float vertices[] = {-1, -1, 0, 1, -1, 0, -1, 1, 0, 1, 1, 0};
vertexBuffer->update(vertices);
auto* indexBuffer = _device->createBuffer({
gfx::BufferUsageBit::INDEX | gfx::BufferUsageBit::TRANSFER_DST,
gfx::MemoryUsageBit::DEVICE,
6 * sizeof(uint16_t),
sizeof(uint16_t),
});
const uint16_t indices[] = {0, 2, 1, 2, 1, 3};
indexBuffer->update(indices);
gfx::BufferList vbReference;
vbReference.emplace_back(vertexBuffer);
_maskModelMesh = ccnew RenderingSubMesh(vbReference, _maskAttributes, _primitiveMode, indexBuffer);
_maskModelMesh->setSubMeshIdx(0);
_maskClearModel->initSubModel(0, _maskModelMesh, _maskClearMtl);
}
}
} // namespace cc

View File

@@ -0,0 +1,203 @@
/****************************************************************************
Copyright (c) 2019-2021 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include "2d/renderer/RenderDrawInfo.h"
#include "2d/renderer/RenderEntity.h"
#include "2d/renderer/UIMeshBuffer.h"
#include "base/Macros.h"
#include "base/Ptr.h"
#include "base/TypeDef.h"
#include "core/assets/Material.h"
#include "core/memop/Pool.h"
#include "renderer/gfx-base/GFXTexture.h"
#include "renderer/gfx-base/states/GFXSampler.h"
#include "scene/DrawBatch2D.h"
namespace cc {
class Root;
using UIMeshBufferArray = ccstd::vector<UIMeshBuffer*>;
using UIMeshBufferMap = ccstd::unordered_map<uint16_t, UIMeshBufferArray>;
class Batcher2d final {
public:
Batcher2d();
explicit Batcher2d(Root* root);
~Batcher2d();
void syncMeshBuffersToNative(uint16_t accId, ccstd::vector<UIMeshBuffer*>&& buffers);
bool initialize();
void update();
void uploadBuffers();
void reset();
void syncRootNodesToNative(ccstd::vector<Node*>&& rootNodes);
void releaseDescriptorSetCache(gfx::Texture* texture, gfx::Sampler* sampler);
UIMeshBuffer* getMeshBuffer(uint16_t accId, uint16_t bufferId);
gfx::Device* getDevice();
inline ccstd::vector<gfx::Attribute>* getDefaultAttribute() { return &_attributes; }
void updateDescriptorSet();
void fillBuffersAndMergeBatches();
void walk(Node* node, float parentOpacity);
void handlePostRender(RenderEntity* entity);
void handleDrawInfo(RenderEntity* entity, RenderDrawInfo* drawInfo, Node* node);
void handleComponentDraw(RenderEntity* entity, RenderDrawInfo* drawInfo, Node* node);
void handleModelDraw(RenderEntity* entity, RenderDrawInfo* drawInfo);
void handleMiddlewareDraw(RenderEntity* entity, RenderDrawInfo* drawInfo);
void handleSubNode(RenderEntity* entity, RenderDrawInfo* drawInfo);
void generateBatch(RenderEntity* entity, RenderDrawInfo* drawInfo);
void generateBatchForMiddleware(RenderEntity* entity, RenderDrawInfo* drawInfo);
void resetRenderStates();
private:
bool _isInit = false;
inline void fillIndexBuffers(RenderDrawInfo* drawInfo) { // NOLINT(readability-convert-member-functions-to-static)
uint16_t* ib = drawInfo->getIDataBuffer();
UIMeshBuffer* buffer = drawInfo->getMeshBuffer();
uint32_t indexOffset = buffer->getIndexOffset();
uint16_t* indexb = drawInfo->getIbBuffer();
uint32_t indexCount = drawInfo->getIbCount();
memcpy(&ib[indexOffset], indexb, indexCount * sizeof(uint16_t));
indexOffset += indexCount;
buffer->setIndexOffset(indexOffset);
}
inline void fillVertexBuffers(RenderEntity* entity, RenderDrawInfo* drawInfo) { // NOLINT(readability-convert-member-functions-to-static)
Node* node = entity->getNode();
const Mat4& matrix = node->getWorldMatrix();
uint8_t stride = drawInfo->getStride();
uint32_t size = drawInfo->getVbCount() * stride;
float* vbBuffer = drawInfo->getVbBuffer();
for (int i = 0; i < size; i += stride) {
Render2dLayout* curLayout = drawInfo->getRender2dLayout(i);
// make sure that the layout of Vec3 is three consecutive floats
static_assert(sizeof(Vec3) == 3 * sizeof(float));
// cast to reduce value copy instructions
reinterpret_cast<Vec3*>(vbBuffer + i)->transformMat4(curLayout->position, matrix);
}
}
inline void setIndexRange(RenderDrawInfo* drawInfo) { // NOLINT(readability-convert-member-functions-to-static)
UIMeshBuffer* buffer = drawInfo->getMeshBuffer();
uint32_t indexOffset = drawInfo->getIndexOffset();
uint32_t indexCount = drawInfo->getIbCount();
indexOffset += indexCount;
if (buffer->getIndexOffset() < indexOffset) {
buffer->setIndexOffset(indexOffset);
}
}
inline void fillColors(RenderEntity* entity, RenderDrawInfo* drawInfo) { // NOLINT(readability-convert-member-functions-to-static)
Color temp = entity->getColor();
uint8_t stride = drawInfo->getStride();
uint32_t size = drawInfo->getVbCount() * stride;
float* vbBuffer = drawInfo->getVbBuffer();
uint32_t offset = 0;
for (int i = 0; i < size; i += stride) {
offset = i + 5;
vbBuffer[offset++] = static_cast<float>(temp.r) / 255.0F;
vbBuffer[offset++] = static_cast<float>(temp.g) / 255.0F;
vbBuffer[offset++] = static_cast<float>(temp.b) / 255.0F;
vbBuffer[offset++] = entity->getOpacity();
}
}
void insertMaskBatch(RenderEntity* entity);
void createClearModel ();
gfx::DescriptorSet* getDescriptorSet(gfx::Texture* texture, gfx::Sampler* sampler, gfx::DescriptorSetLayout* dsLayout);
StencilManager* _stencilManager{nullptr};
// weak reference
Root* _root{nullptr};
// weak reference
ccstd::vector<Node*> _rootNodeArr;
// manage memory manually
ccstd::vector<scene::DrawBatch2D*> _batches;
memop::Pool<scene::DrawBatch2D> _drawBatchPool;
// weak reference
gfx::Device* _device{nullptr}; // use getDevice()
// weak reference
RenderEntity* _currEntity{nullptr};
// weak reference
RenderDrawInfo* _currDrawInfo{nullptr};
// weak reference
UIMeshBuffer* _currMeshBuffer{nullptr};
uint32_t _indexStart{0};
ccstd::hash_t _currHash{0};
uint32_t _currLayer{0};
StencilStage _currStencilStage{StencilStage::DISABLED};
// weak reference
Material* _currMaterial{nullptr};
// weak reference
gfx::Texture* _currTexture{nullptr};
// weak reference
gfx::Sampler* _currSampler{nullptr};
ccstd::hash_t _currSamplerHash{0};
// weak reference
ccstd::vector<RenderDrawInfo*> _meshRenderDrawInfo;
// manage memory manually
ccstd::unordered_map<ccstd::hash_t, gfx::DescriptorSet*> _descriptorSetCache;
gfx::DescriptorSetInfo _dsInfo;
UIMeshBufferMap _meshBuffersMap;
// DefaultAttribute
ccstd::vector<gfx::Attribute> _attributes{
gfx::Attribute{gfx::ATTR_NAME_POSITION, gfx::Format::RGB32F},
gfx::Attribute{gfx::ATTR_NAME_TEX_COORD, gfx::Format::RG32F},
gfx::Attribute{gfx::ATTR_NAME_COLOR, gfx::Format::RGBA32F},
};
// Mask use
IntrusivePtr<scene::Model> _maskClearModel;
IntrusivePtr<Material> _maskClearMtl;
IntrusivePtr<RenderingSubMesh> _maskModelMesh;
ccstd::vector<gfx::Attribute> _maskAttributes{
gfx::Attribute{gfx::ATTR_NAME_POSITION, gfx::Format::RGB32F},
};
gfx::PrimitiveMode _primitiveMode{gfx::PrimitiveMode::TRIANGLE_LIST};
CC_DISALLOW_COPY_MOVE_ASSIGN(Batcher2d);
};
} // namespace cc

View File

@@ -0,0 +1,116 @@
/****************************************************************************
Copyright (c) 2019-2021 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "2d/renderer/RenderEntity.h"
#include "2d/renderer/Batcher2d.h"
#include "bindings/utils/BindingUtils.h"
namespace cc {
RenderEntity::RenderEntity(RenderEntityType type) : _renderEntityType(type) {
if (type == RenderEntityType::STATIC) {
ccnew_placement(&_staticDrawInfos) std::array<RenderDrawInfo, RenderEntity::STATIC_DRAW_INFO_CAPACITY>();
} else {
ccnew_placement(&_dynamicDrawInfos) ccstd::vector<RenderDrawInfo*>();
}
_entitySharedBufferActor.initialize(&_entityAttrLayout, sizeof(EntityAttrLayout));
}
RenderEntity::~RenderEntity() {
if (_renderEntityType == RenderEntityType::STATIC) {
_staticDrawInfos.~array();
} else {
_dynamicDrawInfos.~vector();
}
};
void RenderEntity::addDynamicRenderDrawInfo(RenderDrawInfo* drawInfo) {
CC_ASSERT(_renderEntityType != RenderEntityType::STATIC);
_dynamicDrawInfos.push_back(drawInfo);
}
void RenderEntity::setDynamicRenderDrawInfo(RenderDrawInfo* drawInfo, uint32_t index) {
CC_ASSERT(_renderEntityType != RenderEntityType::STATIC);
if (index < _dynamicDrawInfos.size()) {
_dynamicDrawInfos[index] = drawInfo;
}
}
void RenderEntity::removeDynamicRenderDrawInfo() {
CC_ASSERT(_renderEntityType != RenderEntityType::STATIC);
if (_dynamicDrawInfos.empty()) return;
_dynamicDrawInfos.pop_back(); // warning: memory leaking & crash
}
void RenderEntity::clearDynamicRenderDrawInfos() {
CC_ASSERT(_renderEntityType != RenderEntityType::STATIC);
_dynamicDrawInfos.clear();
}
void RenderEntity::clearStaticRenderDrawInfos() {
CC_ASSERT(_renderEntityType == RenderEntityType::STATIC);
for (uint32_t i = 0; i < _staticDrawInfoSize; i++) {
RenderDrawInfo& drawInfo = _staticDrawInfos[i];
drawInfo.resetDrawInfo();
}
_staticDrawInfoSize = 0;
}
void RenderEntity::setNode(Node* node) {
if (_node) {
_node->setUserData(nullptr);
}
_node = node;
if (_node) {
_node->setUserData(this);
}
}
void RenderEntity::setRenderTransform(Node* renderTransform) {
_renderTransform = renderTransform;
}
RenderDrawInfo* RenderEntity::getDynamicRenderDrawInfo(uint32_t index) {
CC_ASSERT(_renderEntityType != RenderEntityType::STATIC);
if (index >= _dynamicDrawInfos.size()) {
return nullptr;
}
return _dynamicDrawInfos[index];
}
ccstd::vector<RenderDrawInfo*>& RenderEntity::getDynamicRenderDrawInfos() {
CC_ASSERT(_renderEntityType != RenderEntityType::STATIC);
return _dynamicDrawInfos;
}
void RenderEntity::setStaticDrawInfoSize(uint32_t size) {
CC_ASSERT(_renderEntityType == RenderEntityType::STATIC && size <= RenderEntity::STATIC_DRAW_INFO_CAPACITY);
_staticDrawInfoSize = size;
}
RenderDrawInfo* RenderEntity::getStaticRenderDrawInfo(uint32_t index) {
CC_ASSERT(_renderEntityType == RenderEntityType::STATIC && index < _staticDrawInfoSize);
return &(_staticDrawInfos[index]);
}
std::array<RenderDrawInfo, RenderEntity::STATIC_DRAW_INFO_CAPACITY>& RenderEntity::getStaticRenderDrawInfos() {
CC_ASSERT(_renderEntityType == RenderEntityType::STATIC);
return _staticDrawInfos;
}
} // namespace cc

View File

@@ -0,0 +1,159 @@
/****************************************************************************
Copyright (c) 2019-2021 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include <array>
#include "2d/renderer/RenderDrawInfo.h"
#include "2d/renderer/StencilManager.h"
#include "base/Macros.h"
#include "base/TypeDef.h"
#include "bindings/utils/BindingUtils.h"
#include "core/ArrayBuffer.h"
#include "core/scene-graph/Node.h"
namespace cc {
class Batcher2d;
enum class RenderEntityType : uint8_t {
STATIC,
DYNAMIC,
CROSSED,
};
enum class MaskMode : uint8_t {
NONE,
MASK,
MASK_INVERTED,
MASK_NODE,
MASK_NODE_INVERTED
};
struct EntityAttrLayout {
float localOpacity{1.0F};
uint8_t colorR{255};
uint8_t colorG{255};
uint8_t colorB{255};
uint8_t colorA{255};
uint8_t maskMode{0};
uint8_t colorDirtyBit{1};
uint8_t enabledIndex{0};
uint8_t useLocal{0};
};
class RenderEntity final : public Node::UserData {
public:
static constexpr uint32_t STATIC_DRAW_INFO_CAPACITY = 4;
explicit RenderEntity(RenderEntityType type);
~RenderEntity() override;
void addDynamicRenderDrawInfo(RenderDrawInfo* drawInfo);
void setDynamicRenderDrawInfo(RenderDrawInfo* drawInfo, uint32_t index);
void removeDynamicRenderDrawInfo();
void clearDynamicRenderDrawInfos();
void clearStaticRenderDrawInfos();
inline bool getIsMask() const {
return static_cast<MaskMode>(_entityAttrLayout.maskMode) == MaskMode::MASK || static_cast<MaskMode>(_entityAttrLayout.maskMode) == MaskMode::MASK_INVERTED;
}
inline bool getIsSubMask() const {
return static_cast<MaskMode>(_entityAttrLayout.maskMode) == MaskMode::MASK_NODE || static_cast<MaskMode>(_entityAttrLayout.maskMode) == MaskMode::MASK_NODE_INVERTED;
}
inline bool getIsMaskInverted() const {
return static_cast<MaskMode>(_entityAttrLayout.maskMode) == MaskMode::MASK_INVERTED || static_cast<MaskMode>(_entityAttrLayout.maskMode) == MaskMode::MASK_NODE_INVERTED;
}
inline bool getUseLocal() const { return _entityAttrLayout.useLocal; }
inline void setUseLocal(bool useLocal) {
_entityAttrLayout.useLocal = useLocal;
}
inline Node* getNode() const { return _node; }
void setNode(Node* node);
inline Node* getRenderTransform() const { return _renderTransform; }
void setRenderTransform(Node* renderTransform);
inline uint32_t getStencilStage() const { return static_cast<uint32_t>(_stencilStage); }
inline void setStencilStage(uint32_t stage) {
_stencilStage = static_cast<StencilStage>(stage);
}
inline StencilStage getEnumStencilStage() const { return _stencilStage; }
inline void setEnumStencilStage(StencilStage stage) {
_stencilStage = stage;
}
inline RenderEntityType getRenderEntityType() const { return _renderEntityType; };
inline uint32_t getStaticDrawInfoSize() const { return _staticDrawInfoSize; };
void setStaticDrawInfoSize(uint32_t size);
RenderDrawInfo* getStaticRenderDrawInfo(uint32_t index);
std::array<RenderDrawInfo, RenderEntity::STATIC_DRAW_INFO_CAPACITY>& getStaticRenderDrawInfos();
RenderDrawInfo* getDynamicRenderDrawInfo(uint32_t index);
ccstd::vector<RenderDrawInfo*>& getDynamicRenderDrawInfos();
inline se::Object* getEntitySharedBufferForJS() const { return _entitySharedBufferActor.getSharedArrayBufferObject(); }
inline bool getColorDirty() const { return _entityAttrLayout.colorDirtyBit != 0; }
inline void setColorDirty(bool dirty) { _entityAttrLayout.colorDirtyBit = dirty ? 1 : 0; }
inline bool getVBColorDirty() const { return _vbColorDirty; }
inline void setVBColorDirty(bool vbColorDirty) { _vbColorDirty = vbColorDirty; }
inline Color getColor() const { return Color(_entityAttrLayout.colorR, _entityAttrLayout.colorG, _entityAttrLayout.colorB, _entityAttrLayout.colorA); }
inline float getColorAlpha() const { return static_cast<float>(_entityAttrLayout.colorA) / 255.F; }
inline float getLocalOpacity() const { return _entityAttrLayout.localOpacity; }
inline float getOpacity() const { return _opacity; }
inline void setOpacity(float opacity) { _opacity = opacity; }
inline bool isEnabled() const { return _entityAttrLayout.enabledIndex != 0; }
inline uint32_t getRenderDrawInfosSize() const {
return _renderEntityType == RenderEntityType::STATIC ? _staticDrawInfoSize : static_cast<uint32_t>(_dynamicDrawInfos.size());
}
inline RenderDrawInfo* getRenderDrawInfoAt(uint32_t index) {
return _renderEntityType == RenderEntityType::STATIC ? &(_staticDrawInfos[index]) : _dynamicDrawInfos[index];
}
private:
CC_DISALLOW_COPY_MOVE_ASSIGN(RenderEntity);
// weak reference
Node* _node{nullptr};
// weak reference
Node* _renderTransform{nullptr};
EntityAttrLayout _entityAttrLayout;
float _opacity{1.0F};
bindings::NativeMemorySharedToScriptActor _entitySharedBufferActor;
union {
std::array<RenderDrawInfo, RenderEntity::STATIC_DRAW_INFO_CAPACITY> _staticDrawInfos;
ccstd::vector<RenderDrawInfo*> _dynamicDrawInfos;
};
StencilStage _stencilStage{StencilStage::DISABLED};
RenderEntityType _renderEntityType{RenderEntityType::STATIC};
uint8_t _staticDrawInfoSize{0};
bool _vbColorDirty{true};
};
} // namespace cc

View File

@@ -0,0 +1 @@
cocos creator 3.6.3

View File

@@ -0,0 +1,8 @@
{
"files.associations": {
"array": "cpp",
"initializer_list": "cpp",
"xutility": "cpp",
"algorithm": "cpp"
}
}

View File

@@ -0,0 +1,657 @@
/****************************************************************************
Copyright (c) 2019-2021 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "2d/renderer/Batcher2d.h"
#include "application/ApplicationManager.h"
#include "base/TypeDef.h"
#include "core/Root.h"
#include "editor-support/MiddlewareManager.h"
#include "renderer/pipeline/Define.h"
#include "scene/Pass.h"
#include <algorithm>
namespace cc {
Batcher2d::Batcher2d() : Batcher2d(nullptr) {
}
Batcher2d::Batcher2d(Root* root)
: _drawBatchPool([]() { return ccnew scene::DrawBatch2D(); }, [](auto* obj) { delete obj; }, 10U) {
if (root == nullptr) {
root = Root::getInstance();
}
_root = root;
_device = _root->getDevice();
_stencilManager = StencilManager::getInstance();
// LCC_UI_SORTING_GROUP
rendererCache.reserve(1024);
rendererOrder = false;
}
Batcher2d::~Batcher2d() { // NOLINT
_drawBatchPool.destroy();
for (auto iter : _descriptorSetCache) {
delete iter.second;
}
for (auto* drawBatch : _batches) {
delete drawBatch;
}
_attributes.clear();
if(_maskClearModel != nullptr) {
Root::getInstance()->destroyModel(_maskClearModel);
_maskClearModel = nullptr;
}
if (_maskModelMesh != nullptr) {
_maskModelMesh->destroy();
_maskModelMesh = nullptr;
}
_maskClearMtl = nullptr;
_maskAttributes.clear();
}
void Batcher2d::syncMeshBuffersToNative(uint16_t accId, ccstd::vector<UIMeshBuffer*>&& buffers) {
_meshBuffersMap[accId] = std::move(buffers);
}
UIMeshBuffer* Batcher2d::getMeshBuffer(uint16_t accId, uint16_t bufferId) { // NOLINT(bugprone-easily-swappable-parameters)
const auto& map = _meshBuffersMap[accId];
return map[bufferId];
}
gfx::Device* Batcher2d::getDevice() {
if (_device == nullptr) {
_device = Root::getInstance()->getDevice();
}
return _device;
}
void Batcher2d::updateDescriptorSet() {
}
void Batcher2d::syncRootNodesToNative(ccstd::vector<Node*>&& rootNodes) {
_rootNodeArr = std::move(rootNodes);
}
void Batcher2d::fillBuffersAndMergeBatches() {
for (auto* rootNode : _rootNodeArr) {
walk(rootNode, 1);
// CC_LOG_INFO("-------------- flushRendererCache 1 -------------- %d", _rootNodeArr.size());
flushRendererCache(); // LCC_UI_SORTING_GROUP
generateBatch(_currEntity, _currDrawInfo);
}
}
void Batcher2d::walk(Node* node, float parentOpacity) { // NOLINT(misc-no-recursion)
if (!node->isActiveInHierarchy()) {
return;
}
bool breakWalk = false;
auto* entity = static_cast<RenderEntity*>(node->getUserData());
if (entity) {
if (entity->getColorDirty()) {
float localOpacity = entity->getLocalOpacity();
float localColorAlpha = entity->getColorAlpha();
entity->setOpacity(parentOpacity * localOpacity * localColorAlpha);
entity->setColorDirty(false);
entity->setVBColorDirty(true);
}
// LCC_UI_SORTING_GROUP
if (entity->isEnabled()) {
if(entity->getIsMask()){
// CC_LOG_INFO("-------------- flushRendererCache 2 --------------");
flushRendererCache();
uint32_t size = entity->getRenderDrawInfosSize();
for (uint32_t i = 0; i < size; i++) {
auto* drawInfo = entity->getRenderDrawInfoAt(i);
handleDrawInfo(entity, drawInfo, node);
}
entity->setVBColorDirty(false);
}else{
rendererCache.push_back(entity);
if(entity->getSortingPriority() != 0){
rendererOrder = true;
}
}
}
if (entity->getRenderEntityType() == RenderEntityType::CROSSED) {
breakWalk = true;
}
}
if (!breakWalk) {
const auto& children = node->getChildren();
float thisOpacity = entity ? entity->getOpacity() : parentOpacity;
for (const auto& child : children) {
// we should find parent opacity recursively upwards if it doesn't have an entity.
walk(child, thisOpacity);
}
}
// post assembler
if (_stencilManager->getMaskStackSize() > 0 && entity && entity->isEnabled()) {
handlePostRender(entity);
}
}
void Batcher2d::handlePostRender(RenderEntity* entity) {
bool isMask = entity->getIsMask();
if (isMask) {
// CC_LOG_INFO("-------------- flushRendererCache 3 --------------");
flushRendererCache(); // LCC_UI_SORTING_GROUP
generateBatch(_currEntity, _currDrawInfo);
resetRenderStates();
_stencilManager->exitMask();
}
}
CC_FORCE_INLINE void Batcher2d::handleComponentDraw(RenderEntity* entity, RenderDrawInfo* drawInfo, Node* node) {
ccstd::hash_t dataHash = drawInfo->getDataHash();
if (drawInfo->getIsMeshBuffer()) {
dataHash = 0;
}
// may slow
bool isMask = entity->getIsMask();
if (isMask) {
// Mask subComp
insertMaskBatch(entity);
} else {
entity->setEnumStencilStage(_stencilManager->getStencilStage());
}
auto tempStage = static_cast<StencilStage>(entity->getStencilStage());
if (_currHash != dataHash || dataHash == 0 || _currMaterial != drawInfo->getMaterial() || _currStencilStage != tempStage) {
// CC_LOG_INFO("handleComponentDraw break %u-%u %p-%p %d-%d", _currHash,dataHash, _currMaterial, drawInfo->getMaterial(), _currStencilStage, tempStage);
// Generate a batch if not batching
generateBatch(_currEntity, _currDrawInfo);
if (!drawInfo->getIsMeshBuffer()) {
UIMeshBuffer* buffer = drawInfo->getMeshBuffer();
if (_currMeshBuffer != buffer) {
_currMeshBuffer = buffer;
_indexStart = _currMeshBuffer->getIndexOffset();
}
}
_currHash = dataHash;
_currMaterial = drawInfo->getMaterial();
_currStencilStage = tempStage;
_currLayer = entity->getNode()->getLayer();
_currEntity = entity;
_currDrawInfo = drawInfo;
_currTexture = drawInfo->getTexture();
_currSampler = drawInfo->getSampler();
if (_currSampler == nullptr) {
_currSamplerHash = 0;
} else {
_currSamplerHash = _currSampler->getHash();
}
}
if (!drawInfo->getIsMeshBuffer()) {
if (node->getChangedFlags() || drawInfo->getVertDirty()) {
fillVertexBuffers(entity, drawInfo);
drawInfo->setVertDirty(false);
}
if (entity->getVBColorDirty()) {
fillColors(entity, drawInfo);
}
fillIndexBuffers(drawInfo);
}
if (isMask) {
_stencilManager->enableMask();
}
}
CC_FORCE_INLINE void Batcher2d::handleModelDraw(RenderEntity* entity, RenderDrawInfo* drawInfo) {
generateBatch(_currEntity, _currDrawInfo);
resetRenderStates();
// stencil stage
gfx::DepthStencilState* depthStencil = nullptr;
ccstd::hash_t dssHash = 0;
Material* renderMat = drawInfo->getMaterial();
bool isMask = entity->getIsMask();
if (isMask) {
//Mask Comp
insertMaskBatch(entity);
} else {
entity->setEnumStencilStage(_stencilManager->getStencilStage());
}
StencilStage entityStage = entity->getEnumStencilStage();
depthStencil = _stencilManager->getDepthStencilState(entityStage, renderMat);
dssHash = _stencilManager->getStencilHash(entityStage);
// Model
auto* model = drawInfo->getModel();
if (model == nullptr) return;
auto stamp = CC_CURRENT_ENGINE()->getTotalFrames();
model->updateTransform(stamp);
model->updateUBOs(stamp);
const auto& subModelList = model->getSubModels();
for (const auto& submodel : subModelList) {
auto* curdrawBatch = _drawBatchPool.alloc();
curdrawBatch->setVisFlags(entity->getNode()->getLayer());
curdrawBatch->setModel(model);
curdrawBatch->setInputAssembler(submodel->getInputAssembler());
curdrawBatch->setDescriptorSet(submodel->getDescriptorSet());
curdrawBatch->fillPass(renderMat, depthStencil, dssHash, &(submodel->getPatches()));
_batches.push_back(curdrawBatch);
}
if(isMask) {
_stencilManager->enableMask();
}
}
CC_FORCE_INLINE void Batcher2d::handleMiddlewareDraw(RenderEntity* entity, RenderDrawInfo* drawInfo) {
auto layer = entity->getNode()->getLayer();
Material* material = drawInfo->getMaterial();
auto* texture = drawInfo->getTexture();
auto* sampler = drawInfo->getSampler();
auto* meshBuffer = drawInfo->getMeshBuffer();
// check for merge draw
auto enableBatch = !entity->getUseLocal();
if (enableBatch && _currTexture == texture && _currMeshBuffer == meshBuffer
&& !_currEntity->getUseLocal()
&& material->getHash() == _currMaterial->getHash()
&& drawInfo->getIndexOffset() == _currDrawInfo->getIndexOffset() + _currDrawInfo->getIbCount()
&& layer == _currLayer) {
auto ibCount = _currDrawInfo->getIbCount();
_currDrawInfo->setIbCount(ibCount + drawInfo->getIbCount());
} else {
generateBatch(_currEntity, _currDrawInfo);
_currLayer = layer;
_currMaterial = material;
_currTexture = texture;
_currMeshBuffer = meshBuffer;
_currEntity = entity;
_currDrawInfo = drawInfo;
_currHash = 0;
}
}
CC_FORCE_INLINE void Batcher2d::handleSubNode(RenderEntity* entity, RenderDrawInfo* drawInfo) { // NOLINT
if (drawInfo->getSubNode()) {
walk(drawInfo->getSubNode(), entity->getOpacity());
}
}
CC_FORCE_INLINE void Batcher2d::handleDrawInfo(RenderEntity* entity, RenderDrawInfo* drawInfo, Node* node) { //NOLINT(misc-no-recursion)
CC_ASSERT(entity);
CC_ASSERT(drawInfo);
RenderDrawInfoType drawInfoType = drawInfo->getEnumDrawInfoType();
switch (drawInfoType) {
case RenderDrawInfoType::COMP:
handleComponentDraw(entity, drawInfo, node);
break;
case RenderDrawInfoType::MODEL:
handleModelDraw(entity, drawInfo);
break;
case RenderDrawInfoType::MIDDLEWARE:
handleMiddlewareDraw(entity, drawInfo);
break;
case RenderDrawInfoType::SUB_NODE:
handleSubNode(entity, drawInfo);
break;
default:
break;
}
}
void Batcher2d::generateBatch(RenderEntity* entity, RenderDrawInfo* drawInfo) {
if (drawInfo == nullptr) {
return;
}
if (drawInfo->getEnumDrawInfoType() == RenderDrawInfoType::MIDDLEWARE) {
generateBatchForMiddleware(entity, drawInfo);
return;
}
if (_currMaterial == nullptr) {
return;
}
gfx::InputAssembler* ia = nullptr;
if (drawInfo->getIsMeshBuffer()) {
// Todo MeshBuffer RenderData
ia = drawInfo->requestIA(getDevice());
_meshRenderDrawInfo.emplace_back(drawInfo);
} else {
UIMeshBuffer* currMeshBuffer = drawInfo->getMeshBuffer();
currMeshBuffer->setDirty(true);
ia = currMeshBuffer->requireFreeIA(getDevice());
uint32_t indexCount = currMeshBuffer->getIndexOffset() - _indexStart;
if (ia == nullptr) {
return;
}
ia->setFirstIndex(_indexStart);
ia->setIndexCount(indexCount);
_indexStart = currMeshBuffer->getIndexOffset();
}
_currMeshBuffer = nullptr;
// stencilStage
gfx::DepthStencilState* depthStencil = nullptr;
ccstd::hash_t dssHash = 0;
StencilStage entityStage = entity->getEnumStencilStage();
depthStencil = _stencilManager->getDepthStencilState(entityStage, _currMaterial);
dssHash = _stencilManager->getStencilHash(entityStage);
auto* curdrawBatch = _drawBatchPool.alloc();
curdrawBatch->setVisFlags(_currLayer);
curdrawBatch->setInputAssembler(ia);
curdrawBatch->fillPass(_currMaterial, depthStencil, dssHash);
const auto& pass = curdrawBatch->getPasses().at(0);
if (entity->getUseLocal()) {
drawInfo->updateLocalDescriptorSet(entity->getRenderTransform(), pass->getLocalSetLayout());
curdrawBatch->setDescriptorSet(drawInfo->getLocalDes());
} else {
curdrawBatch->setDescriptorSet(getDescriptorSet(_currTexture, _currSampler, pass->getLocalSetLayout()));
}
_batches.push_back(curdrawBatch);
}
void Batcher2d::generateBatchForMiddleware(RenderEntity* entity, RenderDrawInfo* drawInfo) {
auto layer = entity->getNode()->getLayer();
auto* material = drawInfo->getMaterial();
auto* texture = drawInfo->getTexture();
auto* sampler = drawInfo->getSampler();
auto* meshBuffer = drawInfo->getMeshBuffer();
//set meshbuffer offset
auto indexOffset = drawInfo->getIndexOffset();
auto indexCount = drawInfo->getIbCount();
indexOffset += indexCount;
if (meshBuffer->getIndexOffset() < indexOffset) {
meshBuffer->setIndexOffset(indexOffset);
}
meshBuffer->setDirty(true);
gfx::InputAssembler* ia = meshBuffer->requireFreeIA(getDevice());
ia->setFirstIndex(drawInfo->getIndexOffset());
ia->setIndexCount(drawInfo->getIbCount());
// stencilstage
auto stencilStage = _stencilManager->getStencilStage();
gfx::DepthStencilState* depthStencil = _stencilManager->getDepthStencilState(stencilStage, material);
ccstd::hash_t dssHash = _stencilManager->getStencilHash(stencilStage);
auto* curdrawBatch = _drawBatchPool.alloc();
curdrawBatch->setVisFlags(_currLayer);
curdrawBatch->setInputAssembler(ia);
curdrawBatch->fillPass(material, depthStencil, dssHash);
const auto& pass = curdrawBatch->getPasses().at(0);
if (entity->getUseLocal()) {
drawInfo->updateLocalDescriptorSet(entity->getNode(), pass->getLocalSetLayout());
curdrawBatch->setDescriptorSet(drawInfo->getLocalDes());
} else {
curdrawBatch->setDescriptorSet(getDescriptorSet(texture, sampler, pass->getLocalSetLayout()));
}
_batches.push_back(curdrawBatch);
// make sure next generateBatch return.
resetRenderStates();
_currMeshBuffer = nullptr;
}
void Batcher2d::resetRenderStates() {
_currMaterial = nullptr;
_currTexture = nullptr;
_currSampler = nullptr;
_currSamplerHash = 0;
_currLayer = 0;
_currEntity = nullptr;
_currDrawInfo = nullptr;
}
gfx::DescriptorSet* Batcher2d::getDescriptorSet(gfx::Texture* texture, gfx::Sampler* sampler, gfx::DescriptorSetLayout* dsLayout) {
ccstd::hash_t hash = 2;
size_t textureHash;
if (texture != nullptr) {
textureHash = boost::hash_value(texture);
ccstd::hash_combine(hash, textureHash);
}
if (sampler != nullptr) {
ccstd::hash_combine(hash, sampler->getHash());
}
auto iter = _descriptorSetCache.find(hash);
if (iter != _descriptorSetCache.end()) {
if (texture != nullptr && sampler != nullptr) {
iter->second->bindTexture(static_cast<uint32_t>(pipeline::ModelLocalBindings::SAMPLER_SPRITE), texture);
iter->second->bindSampler(static_cast<uint32_t>(pipeline::ModelLocalBindings::SAMPLER_SPRITE), sampler);
}
iter->second->forceUpdate();
return iter->second;
}
_dsInfo.layout = dsLayout;
auto* ds = getDevice()->createDescriptorSet(_dsInfo);
if (texture != nullptr && sampler != nullptr) {
ds->bindTexture(static_cast<uint32_t>(pipeline::ModelLocalBindings::SAMPLER_SPRITE), texture);
ds->bindSampler(static_cast<uint32_t>(pipeline::ModelLocalBindings::SAMPLER_SPRITE), sampler);
}
ds->update();
_descriptorSetCache.emplace(hash, ds);
return ds;
}
void Batcher2d::releaseDescriptorSetCache(gfx::Texture* texture, gfx::Sampler* sampler) {
ccstd::hash_t hash = 2;
size_t textureHash;
if (texture != nullptr) {
textureHash = boost::hash_value(texture);
ccstd::hash_combine(hash, textureHash);
}
if (sampler != nullptr) {
ccstd::hash_combine(hash, sampler->getHash());
}
auto iter = _descriptorSetCache.find(hash);
if (iter != _descriptorSetCache.end()) {
delete iter->second;
_descriptorSetCache.erase(hash);
}
}
bool Batcher2d::initialize() {
_isInit = true;
return _isInit;
}
void Batcher2d::update() {
fillBuffersAndMergeBatches();
resetRenderStates();
for (const auto& scene : Root::getInstance()->getScenes()) {
for (auto* batch : _batches) {
scene->addBatch(batch);
}
}
}
void Batcher2d::uploadBuffers() {
if (_batches.empty()) {
return;
}
for (auto& meshRenderData : _meshRenderDrawInfo) {
meshRenderData->uploadBuffers();
}
for (auto& map : _meshBuffersMap) {
for (auto& buffer : map.second) {
buffer->uploadBuffers();
buffer->reset();
}
}
updateDescriptorSet();
}
void Batcher2d::reset() {
for (auto& batch : _batches) {
batch->clear();
_drawBatchPool.free(batch);
}
_batches.clear();
for (auto& meshRenderData : _meshRenderDrawInfo) {
meshRenderData->resetMeshIA();
}
_meshRenderDrawInfo.clear();
// meshDataArray
for (auto& map : _meshBuffersMap) {
for (auto& buffer : map.second) {
if (buffer) {
buffer->resetIA();
}
}
}
//meshBuffer cannot clear because it is not transported at every frame.
_currMeshBuffer = nullptr;
_indexStart = 0;
_currHash = 0;
_currLayer = 0;
_currMaterial = nullptr;
_currTexture = nullptr;
_currSampler = nullptr;
// stencilManager
}
void Batcher2d::insertMaskBatch(RenderEntity* entity){
generateBatch(_currEntity, _currDrawInfo);
resetRenderStates();
createClearModel();
_maskClearModel->setNode(entity->getNode());
_maskClearModel->setTransform(entity->getNode());
_stencilManager->pushMask();
auto stage = _stencilManager->clear(entity);
gfx::DepthStencilState* depthStencil = nullptr;
ccstd::hash_t dssHash = 0;
if(_maskClearMtl != nullptr){
depthStencil = _stencilManager->getDepthStencilState(stage, _maskClearMtl);
dssHash = _stencilManager->getStencilHash(stage);
}
// Model
if (_maskClearModel == nullptr) return;
auto stamp = CC_CURRENT_ENGINE()->getTotalFrames();
_maskClearModel->updateTransform(stamp);
_maskClearModel->updateUBOs(stamp);
const auto& subModelList = _maskClearModel->getSubModels();
for (const auto& submodel : subModelList) {
auto* curdrawBatch = _drawBatchPool.alloc();
curdrawBatch->setVisFlags(entity->getNode()->getLayer());
curdrawBatch->setModel(_maskClearModel);
curdrawBatch->setInputAssembler(submodel->getInputAssembler());
curdrawBatch->setDescriptorSet(submodel->getDescriptorSet());
curdrawBatch->fillPass(_maskClearMtl, depthStencil, dssHash, &(submodel->getPatches()));
_batches.push_back(curdrawBatch);
}
_stencilManager->enterLevel(entity);
}
void Batcher2d::createClearModel() {
if (_maskClearModel == nullptr) {
_maskClearMtl = BuiltinResMgr::getInstance()->get<Material>(ccstd::string("default-clear-stencil"));
_maskClearModel = Root::getInstance()->createModel<scene::Model>();
uint32_t stride = 12;// vfmt
auto* vertexBuffer = _device->createBuffer({
gfx::BufferUsageBit::VERTEX | gfx::BufferUsageBit::TRANSFER_DST,
gfx::MemoryUsageBit::DEVICE,
4 * stride,
stride,
});
const float vertices[] = {-1, -1, 0, 1, -1, 0, -1, 1, 0, 1, 1, 0};
vertexBuffer->update(vertices);
auto* indexBuffer = _device->createBuffer({
gfx::BufferUsageBit::INDEX | gfx::BufferUsageBit::TRANSFER_DST,
gfx::MemoryUsageBit::DEVICE,
6 * sizeof(uint16_t),
sizeof(uint16_t),
});
const uint16_t indices[] = {0, 2, 1, 2, 1, 3};
indexBuffer->update(indices);
gfx::BufferList vbReference;
vbReference.emplace_back(vertexBuffer);
_maskModelMesh = ccnew RenderingSubMesh(vbReference, _maskAttributes, _primitiveMode, indexBuffer);
_maskModelMesh->setSubMeshIdx(0);
_maskClearModel->initSubModel(0, _maskModelMesh, _maskClearMtl);
}
}
// LCC_UI_SORTING_GROUP
void Batcher2d::flushRendererCache() {
if(rendererCache.size() > 0){
if(rendererOrder){
std::sort(rendererCache.begin(), rendererCache.end(), [](RenderEntity* a, RenderEntity* b) { return a->getSortingPriority() < b->getSortingPriority(); });
}
// CC_LOG_INFO("flushRendererCache %d", rendererCache.size());
for(ccstd::vector<RenderEntity*>::iterator it = rendererCache.begin(); it != rendererCache.end(); it++)
{
RenderEntity* entity = *it;
// CC_LOG_INFO("%f", entity->getSortingPriority());
uint32_t size = entity->getRenderDrawInfosSize();
for (uint32_t i = 0; i < size; i++) {
auto* drawInfo = entity->getRenderDrawInfoAt(i);
handleDrawInfo(entity, drawInfo, entity->getNode());
}
entity->setVBColorDirty(false);
}
rendererCache.clear();
}
rendererOrder = false;
}
} // namespace cc

View File

@@ -0,0 +1,208 @@
/****************************************************************************
Copyright (c) 2019-2021 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include "2d/renderer/RenderDrawInfo.h"
#include "2d/renderer/RenderEntity.h"
#include "2d/renderer/UIMeshBuffer.h"
#include "base/Macros.h"
#include "base/Ptr.h"
#include "base/TypeDef.h"
#include "core/assets/Material.h"
#include "core/memop/Pool.h"
#include "renderer/gfx-base/GFXTexture.h"
#include "renderer/gfx-base/states/GFXSampler.h"
#include "scene/DrawBatch2D.h"
namespace cc {
class Root;
using UIMeshBufferArray = ccstd::vector<UIMeshBuffer*>;
using UIMeshBufferMap = ccstd::unordered_map<uint16_t, UIMeshBufferArray>;
class Batcher2d final {
public:
Batcher2d();
explicit Batcher2d(Root* root);
~Batcher2d();
void syncMeshBuffersToNative(uint16_t accId, ccstd::vector<UIMeshBuffer*>&& buffers);
bool initialize();
void update();
void uploadBuffers();
void reset();
void syncRootNodesToNative(ccstd::vector<Node*>&& rootNodes);
void releaseDescriptorSetCache(gfx::Texture* texture, gfx::Sampler* sampler);
UIMeshBuffer* getMeshBuffer(uint16_t accId, uint16_t bufferId);
gfx::Device* getDevice();
inline ccstd::vector<gfx::Attribute>* getDefaultAttribute() { return &_attributes; }
void updateDescriptorSet();
void fillBuffersAndMergeBatches();
void walk(Node* node, float parentOpacity);
void handlePostRender(RenderEntity* entity);
void handleDrawInfo(RenderEntity* entity, RenderDrawInfo* drawInfo, Node* node);
void handleComponentDraw(RenderEntity* entity, RenderDrawInfo* drawInfo, Node* node);
void handleModelDraw(RenderEntity* entity, RenderDrawInfo* drawInfo);
void handleMiddlewareDraw(RenderEntity* entity, RenderDrawInfo* drawInfo);
void handleSubNode(RenderEntity* entity, RenderDrawInfo* drawInfo);
void generateBatch(RenderEntity* entity, RenderDrawInfo* drawInfo);
void generateBatchForMiddleware(RenderEntity* entity, RenderDrawInfo* drawInfo);
void resetRenderStates();
private:
bool _isInit = false;
inline void fillIndexBuffers(RenderDrawInfo* drawInfo) { // NOLINT(readability-convert-member-functions-to-static)
uint16_t* ib = drawInfo->getIDataBuffer();
UIMeshBuffer* buffer = drawInfo->getMeshBuffer();
uint32_t indexOffset = buffer->getIndexOffset();
uint16_t* indexb = drawInfo->getIbBuffer();
uint32_t indexCount = drawInfo->getIbCount();
memcpy(&ib[indexOffset], indexb, indexCount * sizeof(uint16_t));
indexOffset += indexCount;
buffer->setIndexOffset(indexOffset);
}
inline void fillVertexBuffers(RenderEntity* entity, RenderDrawInfo* drawInfo) { // NOLINT(readability-convert-member-functions-to-static)
Node* node = entity->getNode();
const Mat4& matrix = node->getWorldMatrix();
uint8_t stride = drawInfo->getStride();
uint32_t size = drawInfo->getVbCount() * stride;
float* vbBuffer = drawInfo->getVbBuffer();
for (int i = 0; i < size; i += stride) {
Render2dLayout* curLayout = drawInfo->getRender2dLayout(i);
// make sure that the layout of Vec3 is three consecutive floats
static_assert(sizeof(Vec3) == 3 * sizeof(float));
// cast to reduce value copy instructions
reinterpret_cast<Vec3*>(vbBuffer + i)->transformMat4(curLayout->position, matrix);
}
}
inline void setIndexRange(RenderDrawInfo* drawInfo) { // NOLINT(readability-convert-member-functions-to-static)
UIMeshBuffer* buffer = drawInfo->getMeshBuffer();
uint32_t indexOffset = drawInfo->getIndexOffset();
uint32_t indexCount = drawInfo->getIbCount();
indexOffset += indexCount;
if (buffer->getIndexOffset() < indexOffset) {
buffer->setIndexOffset(indexOffset);
}
}
inline void fillColors(RenderEntity* entity, RenderDrawInfo* drawInfo) { // NOLINT(readability-convert-member-functions-to-static)
Color temp = entity->getColor();
uint8_t stride = drawInfo->getStride();
uint32_t size = drawInfo->getVbCount() * stride;
float* vbBuffer = drawInfo->getVbBuffer();
uint32_t offset = 0;
for (int i = 0; i < size; i += stride) {
offset = i + 5;
vbBuffer[offset++] = static_cast<float>(temp.r) / 255.0F;
vbBuffer[offset++] = static_cast<float>(temp.g) / 255.0F;
vbBuffer[offset++] = static_cast<float>(temp.b) / 255.0F;
vbBuffer[offset++] = entity->getOpacity();
}
}
void insertMaskBatch(RenderEntity* entity);
void createClearModel ();
// LCC_UI_SORTING_GROUP
ccstd::vector<RenderEntity*> rendererCache;
bool rendererOrder;
void flushRendererCache();
gfx::DescriptorSet* getDescriptorSet(gfx::Texture* texture, gfx::Sampler* sampler, gfx::DescriptorSetLayout* dsLayout);
StencilManager* _stencilManager{nullptr};
// weak reference
Root* _root{nullptr};
// weak reference
ccstd::vector<Node*> _rootNodeArr;
// manage memory manually
ccstd::vector<scene::DrawBatch2D*> _batches;
memop::Pool<scene::DrawBatch2D> _drawBatchPool;
// weak reference
gfx::Device* _device{nullptr}; // use getDevice()
// weak reference
RenderEntity* _currEntity{nullptr};
// weak reference
RenderDrawInfo* _currDrawInfo{nullptr};
// weak reference
UIMeshBuffer* _currMeshBuffer{nullptr};
uint32_t _indexStart{0};
ccstd::hash_t _currHash{0};
uint32_t _currLayer{0};
StencilStage _currStencilStage{StencilStage::DISABLED};
// weak reference
Material* _currMaterial{nullptr};
// weak reference
gfx::Texture* _currTexture{nullptr};
// weak reference
gfx::Sampler* _currSampler{nullptr};
ccstd::hash_t _currSamplerHash{0};
// weak reference
ccstd::vector<RenderDrawInfo*> _meshRenderDrawInfo;
// manage memory manually
ccstd::unordered_map<ccstd::hash_t, gfx::DescriptorSet*> _descriptorSetCache;
gfx::DescriptorSetInfo _dsInfo;
UIMeshBufferMap _meshBuffersMap;
// DefaultAttribute
ccstd::vector<gfx::Attribute> _attributes{
gfx::Attribute{gfx::ATTR_NAME_POSITION, gfx::Format::RGB32F},
gfx::Attribute{gfx::ATTR_NAME_TEX_COORD, gfx::Format::RG32F},
gfx::Attribute{gfx::ATTR_NAME_COLOR, gfx::Format::RGBA32F},
};
// Mask use
IntrusivePtr<scene::Model> _maskClearModel;
IntrusivePtr<Material> _maskClearMtl;
IntrusivePtr<RenderingSubMesh> _maskModelMesh;
ccstd::vector<gfx::Attribute> _maskAttributes{
gfx::Attribute{gfx::ATTR_NAME_POSITION, gfx::Format::RGB32F},
};
gfx::PrimitiveMode _primitiveMode{gfx::PrimitiveMode::TRIANGLE_LIST};
CC_DISALLOW_COPY_MOVE_ASSIGN(Batcher2d);
};
} // namespace cc

View File

@@ -0,0 +1,116 @@
/****************************************************************************
Copyright (c) 2019-2021 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "2d/renderer/RenderEntity.h"
#include "2d/renderer/Batcher2d.h"
#include "bindings/utils/BindingUtils.h"
namespace cc {
RenderEntity::RenderEntity(RenderEntityType type) : _renderEntityType(type) {
if (type == RenderEntityType::STATIC) {
ccnew_placement(&_staticDrawInfos) std::array<RenderDrawInfo, RenderEntity::STATIC_DRAW_INFO_CAPACITY>();
} else {
ccnew_placement(&_dynamicDrawInfos) ccstd::vector<RenderDrawInfo*>();
}
_entitySharedBufferActor.initialize(&_entityAttrLayout, sizeof(EntityAttrLayout));
}
RenderEntity::~RenderEntity() {
if (_renderEntityType == RenderEntityType::STATIC) {
_staticDrawInfos.~array();
} else {
_dynamicDrawInfos.~vector();
}
};
void RenderEntity::addDynamicRenderDrawInfo(RenderDrawInfo* drawInfo) {
CC_ASSERT(_renderEntityType != RenderEntityType::STATIC);
_dynamicDrawInfos.push_back(drawInfo);
}
void RenderEntity::setDynamicRenderDrawInfo(RenderDrawInfo* drawInfo, uint32_t index) {
CC_ASSERT(_renderEntityType != RenderEntityType::STATIC);
if (index < _dynamicDrawInfos.size()) {
_dynamicDrawInfos[index] = drawInfo;
}
}
void RenderEntity::removeDynamicRenderDrawInfo() {
CC_ASSERT(_renderEntityType != RenderEntityType::STATIC);
if (_dynamicDrawInfos.empty()) return;
_dynamicDrawInfos.pop_back(); // warning: memory leaking & crash
}
void RenderEntity::clearDynamicRenderDrawInfos() {
CC_ASSERT(_renderEntityType != RenderEntityType::STATIC);
_dynamicDrawInfos.clear();
}
void RenderEntity::clearStaticRenderDrawInfos() {
CC_ASSERT(_renderEntityType == RenderEntityType::STATIC);
for (uint32_t i = 0; i < _staticDrawInfoSize; i++) {
RenderDrawInfo& drawInfo = _staticDrawInfos[i];
drawInfo.resetDrawInfo();
}
_staticDrawInfoSize = 0;
}
void RenderEntity::setNode(Node* node) {
if (_node) {
_node->setUserData(nullptr);
}
_node = node;
if (_node) {
_node->setUserData(this);
}
}
void RenderEntity::setRenderTransform(Node* renderTransform) {
_renderTransform = renderTransform;
}
RenderDrawInfo* RenderEntity::getDynamicRenderDrawInfo(uint32_t index) {
CC_ASSERT(_renderEntityType != RenderEntityType::STATIC);
if (index >= _dynamicDrawInfos.size()) {
return nullptr;
}
return _dynamicDrawInfos[index];
}
ccstd::vector<RenderDrawInfo*>& RenderEntity::getDynamicRenderDrawInfos() {
CC_ASSERT(_renderEntityType != RenderEntityType::STATIC);
return _dynamicDrawInfos;
}
void RenderEntity::setStaticDrawInfoSize(uint32_t size) {
CC_ASSERT(_renderEntityType == RenderEntityType::STATIC && size <= RenderEntity::STATIC_DRAW_INFO_CAPACITY);
_staticDrawInfoSize = size;
}
RenderDrawInfo* RenderEntity::getStaticRenderDrawInfo(uint32_t index) {
CC_ASSERT(_renderEntityType == RenderEntityType::STATIC && index < _staticDrawInfoSize);
return &(_staticDrawInfos[index]);
}
std::array<RenderDrawInfo, RenderEntity::STATIC_DRAW_INFO_CAPACITY>& RenderEntity::getStaticRenderDrawInfos() {
CC_ASSERT(_renderEntityType == RenderEntityType::STATIC);
return _staticDrawInfos;
}
} // namespace cc

View File

@@ -0,0 +1,161 @@
/****************************************************************************
Copyright (c) 2019-2021 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#pragma once
#include <array>
#include "2d/renderer/RenderDrawInfo.h"
#include "2d/renderer/StencilManager.h"
#include "base/Macros.h"
#include "base/TypeDef.h"
#include "bindings/utils/BindingUtils.h"
#include "core/ArrayBuffer.h"
#include "core/scene-graph/Node.h"
namespace cc {
class Batcher2d;
enum class RenderEntityType : uint8_t {
STATIC,
DYNAMIC,
CROSSED,
};
enum class MaskMode : uint8_t {
NONE,
MASK,
MASK_INVERTED,
MASK_NODE,
MASK_NODE_INVERTED
};
struct EntityAttrLayout {
float localOpacity{1.0F};
float sortingPriority{0.0F}; // LCC_UI_SORTING_GROUP
uint8_t colorR{255};
uint8_t colorG{255};
uint8_t colorB{255};
uint8_t colorA{255};
uint8_t maskMode{0};
uint8_t colorDirtyBit{1};
uint8_t enabledIndex{0};
uint8_t useLocal{0};
};
class RenderEntity final : public Node::UserData {
public:
static constexpr uint32_t STATIC_DRAW_INFO_CAPACITY = 4;
explicit RenderEntity(RenderEntityType type);
~RenderEntity() override;
void addDynamicRenderDrawInfo(RenderDrawInfo* drawInfo);
void setDynamicRenderDrawInfo(RenderDrawInfo* drawInfo, uint32_t index);
void removeDynamicRenderDrawInfo();
void clearDynamicRenderDrawInfos();
void clearStaticRenderDrawInfos();
inline bool getIsMask() const {
return static_cast<MaskMode>(_entityAttrLayout.maskMode) == MaskMode::MASK || static_cast<MaskMode>(_entityAttrLayout.maskMode) == MaskMode::MASK_INVERTED;
}
inline bool getIsSubMask() const {
return static_cast<MaskMode>(_entityAttrLayout.maskMode) == MaskMode::MASK_NODE || static_cast<MaskMode>(_entityAttrLayout.maskMode) == MaskMode::MASK_NODE_INVERTED;
}
inline bool getIsMaskInverted() const {
return static_cast<MaskMode>(_entityAttrLayout.maskMode) == MaskMode::MASK_INVERTED || static_cast<MaskMode>(_entityAttrLayout.maskMode) == MaskMode::MASK_NODE_INVERTED;
}
inline bool getUseLocal() const { return _entityAttrLayout.useLocal; }
inline void setUseLocal(bool useLocal) {
_entityAttrLayout.useLocal = useLocal;
}
inline Node* getNode() const { return _node; }
void setNode(Node* node);
inline Node* getRenderTransform() const { return _renderTransform; }
void setRenderTransform(Node* renderTransform);
inline uint32_t getStencilStage() const { return static_cast<uint32_t>(_stencilStage); }
inline void setStencilStage(uint32_t stage) {
_stencilStage = static_cast<StencilStage>(stage);
}
inline StencilStage getEnumStencilStage() const { return _stencilStage; }
inline void setEnumStencilStage(StencilStage stage) {
_stencilStage = stage;
}
inline RenderEntityType getRenderEntityType() const { return _renderEntityType; };
inline uint32_t getStaticDrawInfoSize() const { return _staticDrawInfoSize; };
void setStaticDrawInfoSize(uint32_t size);
RenderDrawInfo* getStaticRenderDrawInfo(uint32_t index);
std::array<RenderDrawInfo, RenderEntity::STATIC_DRAW_INFO_CAPACITY>& getStaticRenderDrawInfos();
RenderDrawInfo* getDynamicRenderDrawInfo(uint32_t index);
ccstd::vector<RenderDrawInfo*>& getDynamicRenderDrawInfos();
inline se::Object* getEntitySharedBufferForJS() const { return _entitySharedBufferActor.getSharedArrayBufferObject(); }
inline bool getColorDirty() const { return _entityAttrLayout.colorDirtyBit != 0; }
inline void setColorDirty(bool dirty) { _entityAttrLayout.colorDirtyBit = dirty ? 1 : 0; }
inline bool getVBColorDirty() const { return _vbColorDirty; }
inline void setVBColorDirty(bool vbColorDirty) { _vbColorDirty = vbColorDirty; }
inline Color getColor() const { return Color(_entityAttrLayout.colorR, _entityAttrLayout.colorG, _entityAttrLayout.colorB, _entityAttrLayout.colorA); }
inline float getColorAlpha() const { return static_cast<float>(_entityAttrLayout.colorA) / 255.F; }
inline float getLocalOpacity() const { return _entityAttrLayout.localOpacity; }
inline float getSortingPriority() const { return _entityAttrLayout.sortingPriority; } // LCC_UI_SORTING_GROUP
inline float getOpacity() const { return _opacity; }
inline void setOpacity(float opacity) { _opacity = opacity; }
inline bool isEnabled() const { return _entityAttrLayout.enabledIndex != 0; }
inline uint32_t getRenderDrawInfosSize() const {
return _renderEntityType == RenderEntityType::STATIC ? _staticDrawInfoSize : static_cast<uint32_t>(_dynamicDrawInfos.size());
}
inline RenderDrawInfo* getRenderDrawInfoAt(uint32_t index) {
return _renderEntityType == RenderEntityType::STATIC ? &(_staticDrawInfos[index]) : _dynamicDrawInfos[index];
}
private:
CC_DISALLOW_COPY_MOVE_ASSIGN(RenderEntity);
// weak reference
Node* _node{nullptr};
// weak reference
Node* _renderTransform{nullptr};
EntityAttrLayout _entityAttrLayout;
float _opacity{1.0F};
bindings::NativeMemorySharedToScriptActor _entitySharedBufferActor;
union {
std::array<RenderDrawInfo, RenderEntity::STATIC_DRAW_INFO_CAPACITY> _staticDrawInfos;
ccstd::vector<RenderDrawInfo*> _dynamicDrawInfos;
};
StencilStage _stencilStage{StencilStage::DISABLED};
RenderEntityType _renderEntityType{RenderEntityType::STATIC};
uint8_t _staticDrawInfoSize{0};
bool _vbColorDirty{true};
};
} // namespace cc