no message
This commit is contained in:
614
cocos/2d/renderer/Batcher2d.cpp
Normal file
614
cocos/2d/renderer/Batcher2d.cpp
Normal file
@@ -0,0 +1,614 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2019-2023 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 documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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 "core/scene-graph/Scene.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() {
|
||||
size_t index = 0;
|
||||
for (auto* rootNode : _rootNodeArr) {
|
||||
// _batches will add by generateBatch
|
||||
walk(rootNode, 1);
|
||||
generateBatch(_currEntity, _currDrawInfo);
|
||||
|
||||
auto* scene = rootNode->getScene()->getRenderScene();
|
||||
size_t const count = _batches.size();
|
||||
for (size_t i = index; i < count; i++) {
|
||||
scene->addBatch(_batches.at(i));
|
||||
}
|
||||
index = count;
|
||||
}
|
||||
}
|
||||
|
||||
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 (math::isEqualF(entity->getOpacity(), 0)) {
|
||||
breakWalk = true;
|
||||
} else 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;
|
||||
|
||||
uint32_t indexOffset = 0;
|
||||
uint32_t indexCount = 0;
|
||||
if (drawInfo->getIsMeshBuffer()) {
|
||||
// Todo MeshBuffer RenderData
|
||||
ia = drawInfo->requestIA(getDevice());
|
||||
indexOffset = drawInfo->getIndexOffset();
|
||||
indexCount = drawInfo->getIbCount();
|
||||
_meshRenderDrawInfo.emplace_back(drawInfo);
|
||||
} else {
|
||||
UIMeshBuffer* currMeshBuffer = drawInfo->getMeshBuffer();
|
||||
|
||||
currMeshBuffer->setDirty(true);
|
||||
|
||||
ia = currMeshBuffer->requireFreeIA(getDevice());
|
||||
indexCount = currMeshBuffer->getIndexOffset() - _indexStart;
|
||||
if (ia == nullptr) {
|
||||
return;
|
||||
}
|
||||
indexOffset = _indexStart;
|
||||
_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->setFirstIndex(indexOffset);
|
||||
curdrawBatch->setIndexCount(indexCount);
|
||||
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());
|
||||
|
||||
// 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->setFirstIndex(drawInfo->getIndexOffset());
|
||||
curdrawBatch->setIndexCount(drawInfo->getIbCount());
|
||||
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, const 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();
|
||||
}
|
||||
|
||||
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
|
||||
202
cocos/2d/renderer/Batcher2d.h
Normal file
202
cocos/2d/renderer/Batcher2d.h
Normal file
@@ -0,0 +1,202 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2019-2023 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 documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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, const 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
|
||||
136
cocos/2d/renderer/RenderDrawInfo.cpp
Normal file
136
cocos/2d/renderer/RenderDrawInfo.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2019-2023 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 documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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/RenderDrawInfo.h"
|
||||
#include "2d/renderer/Batcher2d.h"
|
||||
#include "base/TypeDef.h"
|
||||
#include "core/Root.h"
|
||||
#include "renderer/gfx-base/GFXDevice.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
static gfx::DescriptorSetInfo gDsInfo;
|
||||
static float matrixData[pipeline::UBOLocal::COUNT] = {0.F};
|
||||
void mat4ToFloatArray(const cc::Mat4& mat, float* out, index_t ofs = 0) {
|
||||
memcpy(out + ofs, mat.m, 16 * sizeof(float));
|
||||
}
|
||||
|
||||
RenderDrawInfo::RenderDrawInfo() {
|
||||
_attrSharedBufferActor.initialize(&_drawInfoAttrs, sizeof(_drawInfoAttrs));
|
||||
}
|
||||
|
||||
RenderDrawInfo::~RenderDrawInfo() {
|
||||
destroy();
|
||||
}
|
||||
|
||||
void RenderDrawInfo::changeMeshBuffer() {
|
||||
CC_ASSERT(Root::getInstance()->getBatcher2D());
|
||||
_meshBuffer = Root::getInstance()->getBatcher2D()->getMeshBuffer(_drawInfoAttrs._accId, _drawInfoAttrs._bufferId);
|
||||
}
|
||||
|
||||
gfx::InputAssembler* RenderDrawInfo::requestIA(gfx::Device* device) {
|
||||
CC_ASSERT(_drawInfoAttrs._isMeshBuffer && _drawInfoAttrs._drawInfoType == RenderDrawInfoType::COMP);
|
||||
return initIAInfo(device);
|
||||
}
|
||||
|
||||
void RenderDrawInfo::uploadBuffers() {
|
||||
CC_ASSERT(_drawInfoAttrs._isMeshBuffer && _drawInfoAttrs._drawInfoType == RenderDrawInfoType::COMP);
|
||||
if (_drawInfoAttrs._vbCount == 0 || _drawInfoAttrs._ibCount == 0) return;
|
||||
uint32_t size = _drawInfoAttrs._vbCount * 9 * sizeof(float); // magic Number
|
||||
gfx::Buffer* vBuffer = _ia->getVertexBuffers()[0];
|
||||
vBuffer->resize(size);
|
||||
vBuffer->update(_vDataBuffer);
|
||||
gfx::Buffer* iBuffer = _ia->getIndexBuffer();
|
||||
uint32_t iSize = _drawInfoAttrs._ibCount * 2;
|
||||
iBuffer->resize(iSize);
|
||||
iBuffer->update(_iDataBuffer);
|
||||
}
|
||||
|
||||
void RenderDrawInfo::resetMeshIA() { // NOLINT(readability-make-member-function-const)
|
||||
CC_ASSERT(_drawInfoAttrs._isMeshBuffer && _drawInfoAttrs._drawInfoType == RenderDrawInfoType::COMP);
|
||||
}
|
||||
|
||||
void RenderDrawInfo::destroy() {
|
||||
_vb = nullptr;
|
||||
_ib = nullptr;
|
||||
_ia = nullptr;
|
||||
if (_localDSBF) {
|
||||
CC_SAFE_DELETE(_localDSBF->ds);
|
||||
CC_SAFE_DELETE(_localDSBF->uboBuf);
|
||||
CC_SAFE_DELETE(_localDSBF);
|
||||
}
|
||||
}
|
||||
|
||||
gfx::InputAssembler* RenderDrawInfo::initIAInfo(gfx::Device* device) {
|
||||
if (!_ia) {
|
||||
gfx::InputAssemblerInfo iaInfo = {};
|
||||
uint32_t vbStride = 9 * sizeof(float); // magic Number
|
||||
uint32_t ibStride = sizeof(uint16_t);
|
||||
_vb = device->createBuffer({
|
||||
gfx::BufferUsageBit::VERTEX | gfx::BufferUsageBit::TRANSFER_DST,
|
||||
gfx::MemoryUsageBit::DEVICE | gfx::MemoryUsageBit::HOST,
|
||||
vbStride * 3,
|
||||
vbStride,
|
||||
});
|
||||
_ib = device->createBuffer({
|
||||
gfx::BufferUsageBit::INDEX | gfx::BufferUsageBit::TRANSFER_DST,
|
||||
gfx::MemoryUsageBit::DEVICE | gfx::MemoryUsageBit::HOST,
|
||||
ibStride * 3,
|
||||
ibStride,
|
||||
});
|
||||
|
||||
iaInfo.attributes = *(Root::getInstance()->getBatcher2D()->getDefaultAttribute());
|
||||
iaInfo.vertexBuffers.emplace_back(_vb);
|
||||
iaInfo.indexBuffer = _ib;
|
||||
|
||||
_ia = device->createInputAssembler(iaInfo);
|
||||
}
|
||||
return _ia;
|
||||
}
|
||||
|
||||
void RenderDrawInfo::updateLocalDescriptorSet(Node* transform, const gfx::DescriptorSetLayout* dsLayout) {
|
||||
if (_localDSBF == nullptr) {
|
||||
_localDSBF = new LocalDSBF();
|
||||
auto* device = Root::getInstance()->getDevice();
|
||||
gDsInfo.layout = dsLayout;
|
||||
_localDSBF->ds = device->createDescriptorSet(gDsInfo);
|
||||
_localDSBF->uboBuf = device->createBuffer({
|
||||
gfx::BufferUsageBit::UNIFORM | gfx::BufferUsageBit::TRANSFER_DST,
|
||||
gfx::MemoryUsageBit::HOST | gfx::MemoryUsageBit::DEVICE,
|
||||
pipeline::UBOLocal::SIZE,
|
||||
pipeline::UBOLocal::SIZE,
|
||||
});
|
||||
}
|
||||
if (_texture != nullptr && _sampler != nullptr) {
|
||||
_localDSBF->ds->bindTexture(static_cast<uint32_t>(pipeline::ModelLocalBindings::SAMPLER_SPRITE), _texture);
|
||||
_localDSBF->ds->bindSampler(static_cast<uint32_t>(pipeline::ModelLocalBindings::SAMPLER_SPRITE), _sampler);
|
||||
}
|
||||
_localDSBF->ds->bindBuffer(pipeline::UBOLocal::BINDING, _localDSBF->uboBuf);
|
||||
_localDSBF->ds->update();
|
||||
const auto& worldMatrix = transform->getWorldMatrix();
|
||||
mat4ToFloatArray(worldMatrix, matrixData, pipeline::UBOLocal::MAT_WORLD_OFFSET);
|
||||
_localDSBF->uboBuf->update(matrixData);
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
300
cocos/2d/renderer/RenderDrawInfo.h
Normal file
300
cocos/2d/renderer/RenderDrawInfo.h
Normal file
@@ -0,0 +1,300 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2019-2023 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 documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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/UIMeshBuffer.h"
|
||||
#include "base/Ptr.h"
|
||||
#include "base/Macros.h"
|
||||
#include "base/TypeDef.h"
|
||||
#include "bindings/utils/BindingUtils.h"
|
||||
#include "core/ArrayBuffer.h"
|
||||
#include "core/assets/Material.h"
|
||||
#include "core/scene-graph/Node.h"
|
||||
#include "math/Color.h"
|
||||
#include "math/Vec2.h"
|
||||
#include "math/Vec3.h"
|
||||
#include "math/Vec4.h"
|
||||
#include "renderer/gfx-base/states/GFXSampler.h"
|
||||
#include "scene/Model.h"
|
||||
|
||||
namespace cc {
|
||||
struct Render2dLayout {
|
||||
Vec3 position;
|
||||
Vec2 uv;
|
||||
Vec4 color;
|
||||
};
|
||||
|
||||
enum class RenderDrawInfoType : uint8_t {
|
||||
COMP,
|
||||
MODEL,
|
||||
MIDDLEWARE,
|
||||
SUB_NODE,
|
||||
};
|
||||
|
||||
struct LocalDSBF {
|
||||
gfx::DescriptorSet* ds;
|
||||
gfx::Buffer* uboBuf;
|
||||
};
|
||||
|
||||
class Batcher2d;
|
||||
|
||||
class RenderDrawInfo final {
|
||||
public:
|
||||
RenderDrawInfo();
|
||||
~RenderDrawInfo();
|
||||
|
||||
inline uint32_t getDrawInfoType() const { return static_cast<uint32_t>(_drawInfoAttrs._drawInfoType); }
|
||||
inline void setDrawInfoType(uint32_t type) {
|
||||
_drawInfoAttrs._drawInfoType = static_cast<RenderDrawInfoType>(type);
|
||||
}
|
||||
|
||||
inline uint16_t getAccId() const { return _drawInfoAttrs._accId; }
|
||||
inline void setAccId(uint16_t id) {
|
||||
_drawInfoAttrs._accId = id;
|
||||
}
|
||||
|
||||
inline uint16_t getBufferId() const { return _drawInfoAttrs._bufferId; }
|
||||
inline void setBufferId(uint16_t bufferId) {
|
||||
_drawInfoAttrs._bufferId = bufferId;
|
||||
}
|
||||
|
||||
inline uint32_t getVertexOffset() const { return _drawInfoAttrs._vertexOffset; }
|
||||
inline void setVertexOffset(uint32_t vertexOffset) {
|
||||
_drawInfoAttrs._vertexOffset = vertexOffset;
|
||||
}
|
||||
|
||||
inline uint32_t getIndexOffset() const { return _drawInfoAttrs._indexOffset; }
|
||||
inline void setIndexOffset(uint32_t indexOffset) {
|
||||
_drawInfoAttrs._indexOffset = indexOffset;
|
||||
}
|
||||
|
||||
inline uint32_t getVbCount() const { return _drawInfoAttrs._vbCount; }
|
||||
inline void setVbCount(uint32_t vbCount) {
|
||||
_drawInfoAttrs._vbCount = vbCount;
|
||||
}
|
||||
|
||||
inline uint32_t getIbCount() const { return _drawInfoAttrs._ibCount; }
|
||||
inline void setIbCount(uint32_t ibCount) {
|
||||
_drawInfoAttrs._ibCount = ibCount;
|
||||
}
|
||||
|
||||
inline bool getVertDirty() const { return _drawInfoAttrs._vertDirty; }
|
||||
inline void setVertDirty(bool val) {
|
||||
_drawInfoAttrs._vertDirty = val;
|
||||
}
|
||||
|
||||
inline ccstd::hash_t getDataHash() const { return _drawInfoAttrs._dataHash; }
|
||||
inline void setDataHash(ccstd::hash_t dataHash) {
|
||||
_drawInfoAttrs._dataHash = dataHash;
|
||||
}
|
||||
|
||||
inline bool getIsMeshBuffer() const { return _drawInfoAttrs._isMeshBuffer; }
|
||||
inline void setIsMeshBuffer(bool isMeshBuffer) {
|
||||
_drawInfoAttrs._isMeshBuffer = isMeshBuffer;
|
||||
}
|
||||
|
||||
inline uint8_t getStride() const { return _drawInfoAttrs._stride; }
|
||||
inline void setStride(uint8_t stride) {
|
||||
_drawInfoAttrs._stride = stride;
|
||||
}
|
||||
|
||||
inline Material* getMaterial() const { return _material; }
|
||||
inline void setMaterial(Material* material) {
|
||||
_material = material;
|
||||
}
|
||||
|
||||
inline void setMeshBuffer(UIMeshBuffer* meshBuffer) {
|
||||
_meshBuffer = meshBuffer;
|
||||
}
|
||||
inline UIMeshBuffer* getMeshBuffer() const {
|
||||
return _meshBuffer;
|
||||
}
|
||||
|
||||
inline float* getVDataBuffer() const {
|
||||
return _vDataBuffer;
|
||||
}
|
||||
inline void setVDataBuffer(float* vDataBuffer) {
|
||||
_vDataBuffer = vDataBuffer;
|
||||
}
|
||||
inline uint16_t* getIDataBuffer() const {
|
||||
return _iDataBuffer;
|
||||
}
|
||||
|
||||
inline void setIDataBuffer(uint16_t* iDataBuffer) {
|
||||
_iDataBuffer = iDataBuffer;
|
||||
}
|
||||
|
||||
inline gfx::Texture* getTexture() const {
|
||||
return _texture;
|
||||
}
|
||||
|
||||
inline void setTexture(gfx::Texture* texture) {
|
||||
_texture = texture;
|
||||
}
|
||||
|
||||
inline gfx::Sampler* getSampler() const {
|
||||
return _sampler;
|
||||
}
|
||||
|
||||
inline void setSampler(gfx::Sampler* sampler) {
|
||||
_sampler = sampler;
|
||||
}
|
||||
|
||||
inline float* getVbBuffer() const {
|
||||
return _vbBuffer;
|
||||
}
|
||||
|
||||
inline void setVbBuffer(float* vbBuffer) {
|
||||
_vbBuffer = vbBuffer;
|
||||
}
|
||||
|
||||
inline uint16_t* getIbBuffer() const {
|
||||
return _ibBuffer;
|
||||
}
|
||||
|
||||
inline void setIbBuffer(uint16_t* ibBuffer) {
|
||||
_ibBuffer = ibBuffer;
|
||||
}
|
||||
|
||||
inline scene::Model* getModel() const {
|
||||
CC_ASSERT_EQ(_drawInfoAttrs._drawInfoType, RenderDrawInfoType::MODEL);
|
||||
return _model;
|
||||
}
|
||||
|
||||
inline void setModel(scene::Model* model) {
|
||||
CC_ASSERT_EQ(_drawInfoAttrs._drawInfoType, RenderDrawInfoType::MODEL);
|
||||
if (_drawInfoAttrs._drawInfoType == RenderDrawInfoType::MODEL) {
|
||||
_model = model;
|
||||
}
|
||||
}
|
||||
|
||||
inline Node* getSubNode() const {
|
||||
CC_ASSERT_EQ(_drawInfoAttrs._drawInfoType, RenderDrawInfoType::SUB_NODE);
|
||||
return _subNode;
|
||||
}
|
||||
inline void setSubNode(Node* node) {
|
||||
CC_ASSERT_EQ(_drawInfoAttrs._drawInfoType, RenderDrawInfoType::SUB_NODE);
|
||||
_subNode = node;
|
||||
}
|
||||
|
||||
void changeMeshBuffer();
|
||||
|
||||
inline RenderDrawInfoType getEnumDrawInfoType() const { return _drawInfoAttrs._drawInfoType; }
|
||||
|
||||
inline void setRender2dBufferToNative(uint8_t* buffer) { // NOLINT(bugprone-easily-swappable-parameters)
|
||||
CC_ASSERT(_drawInfoAttrs._drawInfoType == RenderDrawInfoType::COMP && !_drawInfoAttrs._isMeshBuffer);
|
||||
_sharedBuffer = buffer;
|
||||
}
|
||||
|
||||
inline Render2dLayout* getRender2dLayout(uint32_t dataOffset) const {
|
||||
CC_ASSERT(_drawInfoAttrs._drawInfoType == RenderDrawInfoType::COMP && !_drawInfoAttrs._isMeshBuffer);
|
||||
return reinterpret_cast<Render2dLayout*>(_sharedBuffer + dataOffset * sizeof(float));
|
||||
}
|
||||
|
||||
inline se::Object* getAttrSharedBufferForJS() const { return _attrSharedBufferActor.getSharedArrayBufferObject(); }
|
||||
|
||||
gfx::InputAssembler* requestIA(gfx::Device* device);
|
||||
void uploadBuffers();
|
||||
void resetMeshIA();
|
||||
|
||||
inline gfx::DescriptorSet* getLocalDes() { return _localDSBF->ds; }
|
||||
void updateLocalDescriptorSet(Node* transform, const gfx::DescriptorSetLayout* dsLayout);
|
||||
|
||||
inline void resetDrawInfo() {
|
||||
destroy();
|
||||
|
||||
_drawInfoAttrs._bufferId = 0;
|
||||
_drawInfoAttrs._accId = 0;
|
||||
_drawInfoAttrs._vertexOffset = 0;
|
||||
_drawInfoAttrs._indexOffset = 0;
|
||||
_drawInfoAttrs._vbCount = 0;
|
||||
_drawInfoAttrs._ibCount = 0;
|
||||
_drawInfoAttrs._stride = 0;
|
||||
_drawInfoAttrs._dataHash = 0;
|
||||
_drawInfoAttrs._vertDirty = false;
|
||||
_drawInfoAttrs._isMeshBuffer = false;
|
||||
|
||||
_vbBuffer = nullptr;
|
||||
_ibBuffer = nullptr;
|
||||
_vDataBuffer = nullptr;
|
||||
_iDataBuffer = nullptr;
|
||||
_material = nullptr;
|
||||
_texture = nullptr;
|
||||
_sampler = nullptr;
|
||||
_subNode = nullptr;
|
||||
_model = nullptr;
|
||||
_sharedBuffer = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(RenderDrawInfo);
|
||||
void destroy();
|
||||
|
||||
gfx::InputAssembler* initIAInfo(gfx::Device* device);
|
||||
|
||||
struct DrawInfoAttrs {
|
||||
RenderDrawInfoType _drawInfoType{RenderDrawInfoType::COMP};
|
||||
bool _vertDirty{false};
|
||||
bool _isMeshBuffer{false};
|
||||
uint8_t _stride{0};
|
||||
uint16_t _bufferId{0};
|
||||
uint16_t _accId{0};
|
||||
uint32_t _vertexOffset{0};
|
||||
uint32_t _indexOffset{0};
|
||||
uint32_t _vbCount{0};
|
||||
uint32_t _ibCount{0};
|
||||
ccstd::hash_t _dataHash{0};
|
||||
} _drawInfoAttrs{};
|
||||
|
||||
bindings::NativeMemorySharedToScriptActor _attrSharedBufferActor;
|
||||
// weak reference
|
||||
Material* _material{nullptr};
|
||||
// weak reference
|
||||
float* _vDataBuffer{nullptr};
|
||||
// weak reference
|
||||
uint16_t* _iDataBuffer{nullptr};
|
||||
// weak reference
|
||||
UIMeshBuffer* _meshBuffer{nullptr};
|
||||
// weak reference
|
||||
gfx::Texture* _texture{nullptr};
|
||||
// weak reference
|
||||
gfx::Sampler* _sampler{nullptr};
|
||||
// weak reference
|
||||
float* _vbBuffer{nullptr};
|
||||
// weak reference
|
||||
uint16_t* _ibBuffer{nullptr};
|
||||
|
||||
union {
|
||||
Node* _subNode{nullptr};
|
||||
scene::Model* _model;
|
||||
uint8_t* _sharedBuffer;
|
||||
};
|
||||
LocalDSBF* _localDSBF{nullptr};
|
||||
|
||||
// ia
|
||||
IntrusivePtr<gfx::InputAssembler> _ia;
|
||||
IntrusivePtr<gfx::Buffer> _vb;
|
||||
IntrusivePtr<gfx::Buffer> _ib;
|
||||
};
|
||||
} // namespace cc
|
||||
115
cocos/2d/renderer/RenderEntity.cpp
Normal file
115
cocos/2d/renderer/RenderEntity.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2019-2023 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 documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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_NE(_renderEntityType, RenderEntityType::STATIC);
|
||||
_dynamicDrawInfos.push_back(drawInfo);
|
||||
}
|
||||
void RenderEntity::setDynamicRenderDrawInfo(RenderDrawInfo* drawInfo, uint32_t index) {
|
||||
CC_ASSERT_NE(_renderEntityType, RenderEntityType::STATIC);
|
||||
if (index < _dynamicDrawInfos.size()) {
|
||||
_dynamicDrawInfos[index] = drawInfo;
|
||||
}
|
||||
}
|
||||
void RenderEntity::removeDynamicRenderDrawInfo() {
|
||||
CC_ASSERT_NE(_renderEntityType, RenderEntityType::STATIC);
|
||||
if (_dynamicDrawInfos.empty()) return;
|
||||
_dynamicDrawInfos.pop_back(); // warning: memory leaking & crash
|
||||
}
|
||||
|
||||
void RenderEntity::clearDynamicRenderDrawInfos() {
|
||||
CC_ASSERT_NE(_renderEntityType, RenderEntityType::STATIC);
|
||||
_dynamicDrawInfos.clear();
|
||||
}
|
||||
|
||||
void RenderEntity::clearStaticRenderDrawInfos() {
|
||||
CC_ASSERT_EQ(_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_NE(_renderEntityType, RenderEntityType::STATIC);
|
||||
if (index >= _dynamicDrawInfos.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
return _dynamicDrawInfos[index];
|
||||
}
|
||||
ccstd::vector<RenderDrawInfo*>& RenderEntity::getDynamicRenderDrawInfos() {
|
||||
CC_ASSERT_NE(_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_EQ(_renderEntityType, RenderEntityType::STATIC);
|
||||
return _staticDrawInfos;
|
||||
}
|
||||
} // namespace cc
|
||||
158
cocos/2d/renderer/RenderEntity.h
Normal file
158
cocos/2d/renderer/RenderEntity.h
Normal file
@@ -0,0 +1,158 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2019-2023 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 documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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
|
||||
164
cocos/2d/renderer/StencilManager.cpp
Normal file
164
cocos/2d/renderer/StencilManager.cpp
Normal file
@@ -0,0 +1,164 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2019-2023 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 documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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 "StencilManager.h"
|
||||
#include "2d/renderer/RenderEntity.h"
|
||||
|
||||
namespace cc {
|
||||
namespace {
|
||||
StencilManager* instance = nullptr;
|
||||
}
|
||||
|
||||
StencilManager* StencilManager::getInstance() {
|
||||
if (instance == nullptr) {
|
||||
instance = new StencilManager();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
StencilManager::~StencilManager() {
|
||||
for (auto pair : _cacheStateMap) {
|
||||
CC_SAFE_DELETE(pair.second);
|
||||
}
|
||||
|
||||
for (auto pair : _cacheStateMapWithDepth) {
|
||||
CC_SAFE_DELETE(pair.second);
|
||||
}
|
||||
}
|
||||
|
||||
StencilStage StencilManager::clear(RenderEntity* entity) { // NOLINT(readability-convert-member-functions-to-static)
|
||||
bool inverted = entity->getIsMaskInverted();
|
||||
return inverted ? StencilStage::CLEAR_INVERTED : StencilStage::CLEAR;
|
||||
}
|
||||
|
||||
void StencilManager::enterLevel(RenderEntity* entity) { // NOLINT(readability-convert-member-functions-to-static)
|
||||
bool inverted = entity->getIsMaskInverted();
|
||||
entity->setEnumStencilStage(inverted ? StencilStage::ENTER_LEVEL_INVERTED : StencilStage::ENTER_LEVEL);
|
||||
}
|
||||
|
||||
gfx::DepthStencilState* StencilManager::getDepthStencilState(StencilStage stage, Material* mat) {
|
||||
uint32_t key = 0;
|
||||
bool depthTest = false;
|
||||
bool depthWrite = false;
|
||||
gfx::ComparisonFunc depthFunc = gfx::ComparisonFunc::LESS;
|
||||
auto* cacheMap = &_cacheStateMap;
|
||||
|
||||
if (mat && !mat->getPasses()->empty()) {
|
||||
IntrusivePtr<scene::Pass>& pass = mat->getPasses()->at(0);
|
||||
const gfx::DepthStencilState* dss = pass->getDepthStencilState();
|
||||
uint32_t depthTestValue = 0;
|
||||
uint32_t depthWriteValue = 0;
|
||||
if (dss->depthTest) {
|
||||
depthTestValue = 1;
|
||||
}
|
||||
if (dss->depthWrite) {
|
||||
depthWriteValue = 1;
|
||||
}
|
||||
key = (depthTestValue) | (depthWriteValue << 1) | (static_cast<uint32_t>(dss->depthFunc) << 2) | (static_cast<uint32_t>(stage) << 6) | (_maskStackSize << 9);
|
||||
|
||||
depthTest = dss->depthTest;
|
||||
depthWrite = static_cast<uint32_t>(dss->depthWrite);
|
||||
depthFunc = dss->depthFunc;
|
||||
cacheMap = &_cacheStateMapWithDepth;
|
||||
|
||||
} else {
|
||||
key = ((static_cast<uint32_t>(stage)) << 16) | (_maskStackSize);
|
||||
}
|
||||
|
||||
auto iter = cacheMap->find(key);
|
||||
if (iter != cacheMap->end()) {
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
setDepthStencilStateFromStage(stage);
|
||||
|
||||
auto* depthStencilState = ccnew gfx::DepthStencilState();
|
||||
depthStencilState->depthTest = depthTest;
|
||||
depthStencilState->depthWrite = depthWrite;
|
||||
depthStencilState->depthFunc = depthFunc;
|
||||
depthStencilState->stencilTestFront = _stencilPattern.stencilTest;
|
||||
depthStencilState->stencilFuncFront = _stencilPattern.func;
|
||||
depthStencilState->stencilReadMaskFront = _stencilPattern.stencilMask;
|
||||
depthStencilState->stencilWriteMaskFront = _stencilPattern.writeMask;
|
||||
depthStencilState->stencilFailOpFront = _stencilPattern.failOp;
|
||||
depthStencilState->stencilZFailOpFront = _stencilPattern.zFailOp;
|
||||
depthStencilState->stencilPassOpFront = _stencilPattern.passOp;
|
||||
depthStencilState->stencilRefFront = _stencilPattern.ref;
|
||||
depthStencilState->stencilTestBack = _stencilPattern.stencilTest;
|
||||
depthStencilState->stencilFuncBack = _stencilPattern.func;
|
||||
depthStencilState->stencilReadMaskBack = _stencilPattern.stencilMask;
|
||||
depthStencilState->stencilWriteMaskBack = _stencilPattern.writeMask;
|
||||
depthStencilState->stencilFailOpBack = _stencilPattern.failOp;
|
||||
depthStencilState->stencilZFailOpBack = _stencilPattern.zFailOp;
|
||||
depthStencilState->stencilPassOpBack = _stencilPattern.passOp;
|
||||
depthStencilState->stencilRefBack = _stencilPattern.ref;
|
||||
|
||||
const auto& pair = std::pair<uint32_t, gfx::DepthStencilState*>(key, depthStencilState);
|
||||
cacheMap->insert(pair);
|
||||
|
||||
return depthStencilState;
|
||||
}
|
||||
|
||||
void StencilManager::setDepthStencilStateFromStage(StencilStage stage) {
|
||||
StencilEntity& pattern = _stencilPattern;
|
||||
|
||||
if (stage == StencilStage::DISABLED) {
|
||||
pattern.stencilTest = false;
|
||||
pattern.func = gfx::ComparisonFunc::ALWAYS;
|
||||
pattern.failOp = gfx::StencilOp::KEEP;
|
||||
pattern.stencilMask = pattern.writeMask = 0xffff;
|
||||
pattern.ref = 1;
|
||||
} else {
|
||||
pattern.stencilTest = true;
|
||||
if (stage == StencilStage::ENABLED) {
|
||||
pattern.func = gfx::ComparisonFunc::EQUAL;
|
||||
pattern.failOp = gfx::StencilOp::KEEP;
|
||||
pattern.stencilMask = pattern.ref = getStencilRef();
|
||||
pattern.writeMask = getWriteMask();
|
||||
} else if (stage == StencilStage::CLEAR) {
|
||||
pattern.func = gfx::ComparisonFunc::NEVER;
|
||||
pattern.failOp = gfx::StencilOp::ZERO;
|
||||
pattern.writeMask = getWriteMask();
|
||||
pattern.stencilMask = getWriteMask();
|
||||
pattern.ref = getWriteMask();
|
||||
} else if (stage == StencilStage::CLEAR_INVERTED) {
|
||||
pattern.func = gfx::ComparisonFunc::NEVER;
|
||||
pattern.failOp = gfx::StencilOp::REPLACE;
|
||||
pattern.writeMask = pattern.stencilMask = pattern.ref = getWriteMask();
|
||||
} else if (stage == StencilStage::ENTER_LEVEL) {
|
||||
pattern.func = gfx::ComparisonFunc::NEVER;
|
||||
pattern.failOp = gfx::StencilOp::REPLACE;
|
||||
pattern.writeMask = pattern.stencilMask = pattern.ref = getWriteMask();
|
||||
} else if (stage == StencilStage::ENTER_LEVEL_INVERTED) {
|
||||
pattern.func = gfx::ComparisonFunc::NEVER;
|
||||
pattern.failOp = gfx::StencilOp::ZERO;
|
||||
pattern.writeMask = pattern.stencilMask = pattern.ref = getWriteMask();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StencilManager::setStencilStage(uint32_t stageIndex) {
|
||||
_stage = static_cast<StencilStage>(stageIndex);
|
||||
}
|
||||
} // namespace cc
|
||||
140
cocos/2d/renderer/StencilManager.h
Normal file
140
cocos/2d/renderer/StencilManager.h
Normal file
@@ -0,0 +1,140 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2019-2023 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 documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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 <stack>
|
||||
#include "base/Macros.h"
|
||||
#include "base/TypeDef.h"
|
||||
#include "core/ArrayBuffer.h"
|
||||
#include "core/assets/Material.h"
|
||||
#include "renderer/gfx-base/GFXDef-common.h"
|
||||
#include "scene/Pass.h"
|
||||
|
||||
namespace cc {
|
||||
class RenderEntity;
|
||||
enum class StencilStage : uint8_t {
|
||||
// Stencil disabled
|
||||
DISABLED = 0,
|
||||
// Clear stencil buffer
|
||||
CLEAR = 1,
|
||||
// Entering a new level, should handle new stencil
|
||||
ENTER_LEVEL = 2,
|
||||
// In content
|
||||
ENABLED = 3,
|
||||
// Exiting a level, should restore old stencil or disable
|
||||
EXIT_LEVEL = 4,
|
||||
// Clear stencil buffer & USE INVERTED
|
||||
CLEAR_INVERTED = 5,
|
||||
// Entering a new level & USE INVERTED
|
||||
ENTER_LEVEL_INVERTED = 6
|
||||
};
|
||||
|
||||
struct StencilEntity {
|
||||
uint32_t stencilTest{0};
|
||||
gfx::ComparisonFunc func{gfx::ComparisonFunc::ALWAYS};
|
||||
uint32_t stencilMask{0};
|
||||
uint32_t writeMask{0};
|
||||
gfx::StencilOp failOp{gfx::StencilOp::KEEP};
|
||||
gfx::StencilOp zFailOp{gfx::StencilOp::KEEP};
|
||||
gfx::StencilOp passOp{gfx::StencilOp::KEEP};
|
||||
uint32_t ref{0};
|
||||
};
|
||||
|
||||
class StencilManager final {
|
||||
public:
|
||||
static StencilManager* getInstance();
|
||||
StencilManager() = default;
|
||||
~StencilManager();
|
||||
|
||||
inline StencilStage getStencilStage() const { return _stage; }
|
||||
|
||||
gfx::DepthStencilState* getDepthStencilState(StencilStage stage, Material* mat = nullptr);
|
||||
void setDepthStencilStateFromStage(StencilStage stage);
|
||||
|
||||
inline uint32_t getMaskStackSize() const { return _maskStackSize; }
|
||||
inline void setMaskStackSize(uint32_t size) {
|
||||
_maskStackSize = size;
|
||||
}
|
||||
|
||||
inline void pushMask() {
|
||||
++_maskStackSize;
|
||||
}
|
||||
|
||||
StencilStage clear(RenderEntity* entity);
|
||||
void enterLevel(RenderEntity* entity);
|
||||
|
||||
inline void enableMask() {
|
||||
_stage = StencilStage::ENABLED;
|
||||
}
|
||||
|
||||
inline void exitMask() {
|
||||
if (_maskStackSize == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
--_maskStackSize;
|
||||
if (_maskStackSize == 0) {
|
||||
_stage = StencilStage::DISABLED;
|
||||
} else {
|
||||
_stage = StencilStage::ENABLED;
|
||||
}
|
||||
}
|
||||
|
||||
inline uint32_t getWriteMask() const {
|
||||
return 1 << (_maskStackSize - 1);
|
||||
}
|
||||
|
||||
inline uint32_t getExitWriteMask() const {
|
||||
return 1 << _maskStackSize;
|
||||
}
|
||||
|
||||
inline uint32_t getStencilRef() const {
|
||||
uint32_t result = 0;
|
||||
for (uint32_t i = 0; i < _maskStackSize; i++) {
|
||||
result += (1 << i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline uint32_t getStencilHash(StencilStage stage) const {
|
||||
return ((static_cast<uint32_t>(stage)) << 8) | _maskStackSize;
|
||||
}
|
||||
|
||||
void setStencilStage(uint32_t stageIndex);
|
||||
|
||||
private:
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(StencilManager);
|
||||
|
||||
StencilEntity _stencilPattern;
|
||||
ArrayBuffer::Ptr _stencilSharedBuffer;
|
||||
|
||||
StencilStage _stage{StencilStage::DISABLED};
|
||||
|
||||
uint32_t _maskStackSize{0};
|
||||
|
||||
ccstd::unordered_map<uint32_t, gfx::DepthStencilState*> _cacheStateMap;
|
||||
ccstd::unordered_map<uint32_t, gfx::DepthStencilState*> _cacheStateMapWithDepth;
|
||||
};
|
||||
} // namespace cc
|
||||
178
cocos/2d/renderer/UIMeshBuffer.cpp
Normal file
178
cocos/2d/renderer/UIMeshBuffer.cpp
Normal file
@@ -0,0 +1,178 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2019-2023 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 documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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/UIMeshBuffer.h"
|
||||
#include "renderer/gfx-base/GFXDevice.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
static uint32_t getAttributesStride(ccstd::vector<gfx::Attribute>& attrs) {
|
||||
uint32_t stride = 0;
|
||||
for (auto& attr : attrs) {
|
||||
const auto& info = gfx::GFX_FORMAT_INFOS[static_cast<uint32_t>(attr.format)];
|
||||
stride += info.size;
|
||||
}
|
||||
return stride;
|
||||
}
|
||||
|
||||
UIMeshBuffer::~UIMeshBuffer() {
|
||||
destroy();
|
||||
}
|
||||
|
||||
void UIMeshBuffer::setVData(float* vData) {
|
||||
_vData = vData;
|
||||
}
|
||||
|
||||
void UIMeshBuffer::setIData(uint16_t* iData) {
|
||||
_iData = iData;
|
||||
}
|
||||
|
||||
void UIMeshBuffer::initialize(ccstd::vector<gfx::Attribute>&& attrs, bool needCreateLayout) {
|
||||
_attributes = attrs;
|
||||
_vertexFormatBytes = getAttributesStride(attrs);
|
||||
if (needCreateLayout) {
|
||||
_meshBufferLayout = new MeshBufferLayout();
|
||||
}
|
||||
_needDeleteLayout = needCreateLayout;
|
||||
}
|
||||
|
||||
void UIMeshBuffer::reset() {
|
||||
setIndexOffset(0);
|
||||
_dirty = false;
|
||||
}
|
||||
|
||||
void UIMeshBuffer::resetIA() {
|
||||
}
|
||||
|
||||
void UIMeshBuffer::destroy() {
|
||||
reset();
|
||||
_attributes.clear();
|
||||
_vb = nullptr;
|
||||
_ib = nullptr;
|
||||
if (_needDeleteVData) {
|
||||
delete _vData;
|
||||
delete _iData;
|
||||
}
|
||||
_vData = nullptr;
|
||||
_iData = nullptr;
|
||||
// Destroy InputAssemblers
|
||||
_ia = nullptr;
|
||||
if (_needDeleteLayout) {
|
||||
CC_SAFE_DELETE(_meshBufferLayout);
|
||||
}
|
||||
}
|
||||
|
||||
void UIMeshBuffer::setDirty() {
|
||||
_dirty = true;
|
||||
}
|
||||
|
||||
gfx::InputAssembler* UIMeshBuffer::requireFreeIA(gfx::Device* device) {
|
||||
return createNewIA(device);
|
||||
}
|
||||
|
||||
void UIMeshBuffer::uploadBuffers() {
|
||||
uint32_t byteOffset = getByteOffset();
|
||||
bool dirty = getDirty();
|
||||
if (_meshBufferLayout == nullptr || byteOffset == 0 || !dirty || !_ia) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t indexCount = getIndexOffset();
|
||||
uint32_t byteCount = getByteOffset();
|
||||
|
||||
gfx::BufferList vBuffers = _ia->getVertexBuffers();
|
||||
if (!vBuffers.empty()) {
|
||||
gfx::Buffer* vBuffer = vBuffers[0];
|
||||
if (byteCount > vBuffer->getSize()) {
|
||||
vBuffer->resize(byteCount);
|
||||
}
|
||||
vBuffer->update(_vData);
|
||||
}
|
||||
gfx::Buffer* iBuffer = _ia->getIndexBuffer();
|
||||
if (indexCount * 2 > iBuffer->getSize()) {
|
||||
iBuffer->resize(indexCount * 2);
|
||||
}
|
||||
iBuffer->update(_iData);
|
||||
|
||||
setDirty(false);
|
||||
}
|
||||
|
||||
// use less
|
||||
void UIMeshBuffer::recycleIA(gfx::InputAssembler* ia) {
|
||||
}
|
||||
|
||||
gfx::InputAssembler* UIMeshBuffer::createNewIA(gfx::Device* device) {
|
||||
if (!_ia) {
|
||||
uint32_t vbStride = _vertexFormatBytes;
|
||||
uint32_t ibStride = sizeof(uint16_t);
|
||||
|
||||
gfx::InputAssemblerInfo iaInfo = {};
|
||||
_vb = device->createBuffer({
|
||||
gfx::BufferUsageBit::VERTEX | gfx::BufferUsageBit::TRANSFER_DST,
|
||||
gfx::MemoryUsageBit::DEVICE | gfx::MemoryUsageBit::HOST,
|
||||
vbStride * 3,
|
||||
vbStride,
|
||||
});
|
||||
_ib = device->createBuffer({
|
||||
gfx::BufferUsageBit::INDEX | gfx::BufferUsageBit::TRANSFER_DST,
|
||||
gfx::MemoryUsageBit::DEVICE | gfx::MemoryUsageBit::HOST,
|
||||
ibStride * 3,
|
||||
ibStride,
|
||||
});
|
||||
|
||||
iaInfo.attributes = _attributes;
|
||||
iaInfo.vertexBuffers.emplace_back(_vb);
|
||||
iaInfo.indexBuffer = _ib;
|
||||
_ia = device->createInputAssembler(iaInfo);
|
||||
}
|
||||
|
||||
return _ia;
|
||||
}
|
||||
|
||||
void UIMeshBuffer::syncSharedBufferToNative(uint32_t* buffer) {
|
||||
_sharedBuffer = buffer;
|
||||
parseLayout();
|
||||
}
|
||||
|
||||
void UIMeshBuffer::parseLayout() {
|
||||
_meshBufferLayout = reinterpret_cast<MeshBufferLayout*>(_sharedBuffer);
|
||||
}
|
||||
|
||||
void UIMeshBuffer::setByteOffset(uint32_t byteOffset) {
|
||||
_meshBufferLayout->byteOffset = byteOffset;
|
||||
}
|
||||
|
||||
void UIMeshBuffer::setVertexOffset(uint32_t vertexOffset) {
|
||||
_meshBufferLayout->vertexOffset = vertexOffset;
|
||||
}
|
||||
|
||||
void UIMeshBuffer::setIndexOffset(uint32_t indexOffset) {
|
||||
_meshBufferLayout->indexOffset = indexOffset;
|
||||
}
|
||||
|
||||
void UIMeshBuffer::setDirty(bool dirty) const {
|
||||
_meshBufferLayout->dirtyMark = dirty ? 1 : 0;
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
100
cocos/2d/renderer/UIMeshBuffer.h
Normal file
100
cocos/2d/renderer/UIMeshBuffer.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2019-2023 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 documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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 "base/Ptr.h"
|
||||
#include "base/Macros.h"
|
||||
#include "base/TypeDef.h"
|
||||
#include "renderer/gfx-base/GFXInputAssembler.h"
|
||||
#include "renderer/gfx-base/GFXDef-common.h"
|
||||
#include "renderer/gfx-base/GFXBuffer.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
struct MeshBufferLayout {
|
||||
uint32_t byteOffset;
|
||||
uint32_t vertexOffset;
|
||||
uint32_t indexOffset;
|
||||
uint32_t dirtyMark;
|
||||
};
|
||||
|
||||
class UIMeshBuffer final {
|
||||
public:
|
||||
UIMeshBuffer() = default;
|
||||
~UIMeshBuffer();
|
||||
|
||||
inline float* getVData() const { return _vData; }
|
||||
void setVData(float* vData);
|
||||
inline uint16_t* getIData() const { return _iData; }
|
||||
void setIData(uint16_t* iData);
|
||||
|
||||
void initialize(ccstd::vector<gfx::Attribute>&& attrs, bool needCreateLayout = false);
|
||||
void reset();
|
||||
void destroy();
|
||||
void setDirty();
|
||||
void uploadBuffers();
|
||||
void syncSharedBufferToNative(uint32_t* buffer);
|
||||
void resetIA();
|
||||
void recycleIA(gfx::InputAssembler* ia);
|
||||
void parseLayout();
|
||||
|
||||
gfx::InputAssembler* requireFreeIA(gfx::Device* device);
|
||||
gfx::InputAssembler* createNewIA(gfx::Device* device);
|
||||
|
||||
inline uint32_t getByteOffset() const { return _meshBufferLayout->byteOffset; }
|
||||
void setByteOffset(uint32_t byteOffset);
|
||||
inline uint32_t getVertexOffset() const { return _meshBufferLayout->vertexOffset; }
|
||||
void setVertexOffset(uint32_t vertexOffset);
|
||||
inline uint32_t getIndexOffset() const { return _meshBufferLayout->indexOffset; }
|
||||
void setIndexOffset(uint32_t indexOffset);
|
||||
inline bool getDirty() const { return _meshBufferLayout->dirtyMark != 0; }
|
||||
void setDirty(bool dirty) const;
|
||||
inline const ccstd::vector<gfx::Attribute>& getAttributes() const {
|
||||
return _attributes;
|
||||
}
|
||||
|
||||
protected:
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(UIMeshBuffer);
|
||||
|
||||
private:
|
||||
float* _vData{nullptr};
|
||||
uint16_t* _iData{nullptr};
|
||||
|
||||
MeshBufferLayout* _meshBufferLayout{nullptr};
|
||||
uint32_t* _sharedBuffer{nullptr};
|
||||
|
||||
uint32_t _vertexFormatBytes{0};
|
||||
uint32_t _initVDataCount{0};
|
||||
uint32_t _initIDataCount{0};
|
||||
|
||||
ccstd::vector<gfx::Attribute> _attributes;
|
||||
IntrusivePtr<gfx::InputAssembler> _ia;
|
||||
IntrusivePtr<gfx::Buffer> _vb;
|
||||
IntrusivePtr<gfx::Buffer> _ib;
|
||||
|
||||
bool _dirty{false};
|
||||
bool _needDeleteVData{false};
|
||||
bool _needDeleteLayout{false};
|
||||
};
|
||||
} // namespace cc
|
||||
156
cocos/2d/renderer/UIModelProxy.cpp
Normal file
156
cocos/2d/renderer/UIModelProxy.cpp
Normal file
@@ -0,0 +1,156 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2019-2023 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 documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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 "UIModelProxy.h"
|
||||
#include "2d/renderer/RenderEntity.h"
|
||||
#include "core/assets/RenderingSubMesh.h"
|
||||
|
||||
namespace cc {
|
||||
UIModelProxy::UIModelProxy() {
|
||||
_device = Root::getInstance()->getDevice();
|
||||
}
|
||||
|
||||
UIModelProxy::~UIModelProxy() {
|
||||
destroy();
|
||||
}
|
||||
|
||||
void UIModelProxy::initModel(Node* node) {
|
||||
_model = Root::getInstance()->createModel<scene::Model>();
|
||||
_model->setNode(node);
|
||||
_model->setTransform(node);
|
||||
_node = node;
|
||||
}
|
||||
|
||||
void UIModelProxy::activeSubModels() {
|
||||
if (_model == nullptr) return;
|
||||
auto* entity = static_cast<RenderEntity*>(_node->getUserData());
|
||||
auto drawInfoSize = entity->getDynamicRenderDrawInfos().size();
|
||||
auto subModelSize = _model->getSubModels().size();
|
||||
if (drawInfoSize > subModelSize) {
|
||||
for (size_t i = subModelSize; i < drawInfoSize; i++) {
|
||||
if (_model->getSubModels().size() <= i) {
|
||||
RenderDrawInfo* drawInfo = entity->getDynamicRenderDrawInfo(static_cast<uint32_t>(i));
|
||||
if (drawInfo == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto* vertexBuffer = _device->createBuffer({
|
||||
gfx::BufferUsageBit::VERTEX | gfx::BufferUsageBit::TRANSFER_DST,
|
||||
gfx::MemoryUsageBit::DEVICE,
|
||||
65535 * _stride,
|
||||
_stride,
|
||||
});
|
||||
auto* indexBuffer = _device->createBuffer({
|
||||
gfx::BufferUsageBit::INDEX | gfx::BufferUsageBit::TRANSFER_DST,
|
||||
gfx::MemoryUsageBit::DEVICE,
|
||||
65535 * sizeof(uint16_t) * 2,
|
||||
sizeof(uint16_t),
|
||||
});
|
||||
gfx::BufferList vbReference;
|
||||
vbReference.emplace_back(vertexBuffer);
|
||||
|
||||
auto* renderMesh = ccnew RenderingSubMesh(vbReference, _attributes, _primitiveMode, indexBuffer);
|
||||
renderMesh->setSubMeshIdx(0);
|
||||
|
||||
_model->initSubModel(static_cast<index_t>(i), renderMesh, drawInfo->getMaterial());
|
||||
_graphicsUseSubMeshes.emplace_back(renderMesh);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UIModelProxy::uploadData() {
|
||||
auto* entity = static_cast<RenderEntity*>(_node->getUserData());
|
||||
const auto& drawInfos = entity->getDynamicRenderDrawInfos();
|
||||
const auto& subModelList = _model->getSubModels();
|
||||
for (size_t i = 0; i < drawInfos.size(); i++) {
|
||||
auto* drawInfo = drawInfos[i];
|
||||
auto* ia = subModelList.at(i)->getInputAssembler();
|
||||
if (drawInfo->getVertexOffset() <= 0 || drawInfo->getIndexOffset() <= 0) continue;
|
||||
gfx::BufferList vBuffers = ia->getVertexBuffers();
|
||||
if (!vBuffers.empty()) {
|
||||
auto size = drawInfo->getVertexOffset() * _stride;
|
||||
// if (size > vBuffers[0]->getSize()) {
|
||||
vBuffers[0]->resize(size);
|
||||
// }
|
||||
vBuffers[0]->update(drawInfo->getVDataBuffer()); // vdata
|
||||
}
|
||||
ia->setVertexCount(drawInfo->getVertexOffset()); // count
|
||||
|
||||
gfx::Buffer* iBuffer = ia->getIndexBuffer();
|
||||
auto size = drawInfo->getIndexOffset() * 2;
|
||||
// if (size > iBuffer->getSize()) {
|
||||
iBuffer->resize(size);
|
||||
// }
|
||||
iBuffer->update(drawInfo->getIDataBuffer()); // idata
|
||||
ia->setIndexCount(drawInfo->getIndexOffset()); // indexCount
|
||||
// drawInfo->setModel(_model); // hack, render by model
|
||||
}
|
||||
|
||||
if (!drawInfos.empty()) {
|
||||
drawInfos[0]->setModel(_model);
|
||||
}
|
||||
}
|
||||
|
||||
void UIModelProxy::destroy() {
|
||||
if (_model != nullptr) {
|
||||
Root::getInstance()->destroyModel(_model);
|
||||
_model = nullptr;
|
||||
}
|
||||
|
||||
for (auto& subMesh : _graphicsUseSubMeshes) {
|
||||
subMesh->destroy();
|
||||
subMesh = nullptr;
|
||||
}
|
||||
_graphicsUseSubMeshes.clear();
|
||||
|
||||
_models.clear();
|
||||
}
|
||||
|
||||
void UIModelProxy::clear() {
|
||||
}
|
||||
|
||||
// for ui model
|
||||
void UIModelProxy::updateModels(scene::Model* model) {
|
||||
_models.emplace_back(model);
|
||||
}
|
||||
|
||||
void UIModelProxy::attachDrawInfo() {
|
||||
auto* entity = static_cast<RenderEntity*>(_node->getUserData());
|
||||
auto& drawInfos = entity->getDynamicRenderDrawInfos();
|
||||
if (drawInfos.size() != _models.size()) return;
|
||||
for (size_t i = 0; i < drawInfos.size(); i++) {
|
||||
drawInfos[i]->setModel(_models[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void UIModelProxy::attachNode(Node* node) {
|
||||
_node = node;
|
||||
}
|
||||
|
||||
void UIModelProxy::clearModels() {
|
||||
_models.clear();
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
67
cocos/2d/renderer/UIModelProxy.h
Normal file
67
cocos/2d/renderer/UIModelProxy.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2019-2023 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 documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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 "base/Macros.h"
|
||||
#include "core/Root.h"
|
||||
#include "scene/Model.h"
|
||||
|
||||
namespace cc {
|
||||
class UIModelProxy final {
|
||||
public:
|
||||
UIModelProxy();
|
||||
~UIModelProxy();
|
||||
|
||||
void initModel(Node* node);
|
||||
void activeSubModels();
|
||||
void uploadData();
|
||||
void destroy();
|
||||
void clear();
|
||||
inline scene::Model* getModel() const { return _model; }
|
||||
// For UIModel
|
||||
void updateModels(scene::Model* models);
|
||||
void attachDrawInfo();
|
||||
void attachNode(Node* node);
|
||||
void clearModels();
|
||||
|
||||
protected:
|
||||
CC_DISALLOW_COPY_MOVE_ASSIGN(UIModelProxy);
|
||||
|
||||
private:
|
||||
Node* _node{nullptr};
|
||||
IntrusivePtr<scene::Model> _model;
|
||||
ccstd::vector<IntrusivePtr<RenderingSubMesh>> _graphicsUseSubMeshes{};
|
||||
// For UIModel
|
||||
ccstd::vector<scene::Model*> _models{};
|
||||
|
||||
gfx::Device* _device{nullptr};
|
||||
uint32_t _stride{32};
|
||||
ccstd::vector<gfx::Attribute> _attributes{
|
||||
gfx::Attribute{gfx::ATTR_NAME_POSITION, gfx::Format::RGB32F},
|
||||
gfx::Attribute{gfx::ATTR_NAME_COLOR, gfx::Format::RGBA32F},
|
||||
gfx::Attribute{"a_dist", gfx::Format::R32F},
|
||||
};
|
||||
gfx::PrimitiveMode _primitiveMode{gfx::PrimitiveMode::TRIANGLE_LIST};
|
||||
};
|
||||
} // namespace cc
|
||||
Reference in New Issue
Block a user