发现之前写的自定义渲染,在win32环境下竟然没有生效
发现整个的batcher-2d.update竟然没有生效,在jsb环境下直接返回了
追到最后,整个渲染驱动还是来自batch2d
这个frameMove就是来自jsb层,
还是得先查顶点数据,老办法,从结果倒推。
这里为了调试方便,我构建了win32版本,理论上在c++层的渲染应该是和android大致相同的,只要我们看明白了win32,基本上android也同理。
从glDrawElements下手
思路和之前一样,无论engine的渲染多复杂,最终到opengl这边,他都会使用函数glDrawElements
发现gles2和gles3中都有,尝试下个断点,就会发现到底使用的是哪个,我这里断点到了gles3里面
因为我们的场景上只有一个Sprite,所以提交到glDrawElements的参数肯定是如下结果:
这里你需要了解下
glDrawElements函数对应的参数,这里不再展开。
图元glPrimitive是4,和gl里面的定义是一致的
#define GL_TRIANGLES 0x0004
顶点数量是6?为啥是6?2个三角形,6个顶点,所以是6!
这里检查下参数仅仅是为了二次确认我们的确找到了想要的断点。
顺着drawInfo开始往上推
走到这里,我们发现数据好像是来自Message,从Agent可以看出来是一个代理。
#define ENQUEUE_MESSAGE_2(queue, MessageName, \
Param1, Value1, \
Param2, Value2, \
Code) \
{ \
using Type1 = typename std::decay<decltype(Value1)>::type; \
using Type2 = typename std::decay<decltype(Value2)>::type; \
\
class MessageName final : public Message { \
public: \
MessageName( \
Type1 In##Param1, Type2 In##Param2) \
: Param1(std::move(In##Param1)), \
Param2(std::move(In##Param2)) { \
} \
void execute() override { \
Code \
} \
char const *getName() const noexcept override { \
return (#MessageName); \
} \
\
private: \
Type1 Param1; \
Type2 Param2; \
}; \
WRITE_MESSAGE(queue, MessageName, (Value1, Value2)) \
}
用到了c++模版,的确有点晦涩难懂。到这里我们也不需要深究,可以这么理解,通过消息机制保证的数据的安全和有效性
void CommandBufferAgent::draw(const DrawInfo &info) {
// 在这里派注册一个消息,当消息队列轮训到这个消息时,就执行回调
ENQUEUE_MESSAGE_2(
_messageQueue, CommandBufferDraw,
actor, getActor(),
info, info,
{
// 所以本质上info信息还是来自draw的参数
actor->draw(info);
});
}
继续追踪
再顺着调用栈往上走,发现数据是来自batch->_drawInfo
所以焦点就转向drawInfo的赋值地方,顺着找,发现只有这1个地方,再断点看下何时赋值。
void DrawBatch2D::setInputAssembler(gfx::InputAssembler *ia) {
_inputAssembler = ia;
_drawInfo = _inputAssembler->getDrawInfo();
}
ia走的是下边的逻辑,那么这个ia到底是怎么来的呢
UIMeshBuffer* currMeshBuffer = drawInfo->getMeshBuffer();// 设置meshBuffer也来自jsb
ia = currMeshBuffer->requireFreeIA(getDevice());
gfx::InputAssembler* UIMeshBuffer::requireFreeIA(gfx::Device* device) {
return createNewIA(device);
}
gfx::InputAssembler* UIMeshBuffer::createNewIA(gfx::Device* device) {
// 到这里直接返回了,说明drawInfo->getMeshBuffer()里面早就有值了
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 Batcher2d::fillBuffersAndMergeBatches() {
size_t index = 0;
for (auto* rootNode : _rootNodeArr) {
// _batches will add by generateBatch
walk(rootNode, 1);
generateBatch(_currEntity, _currDrawInfo);// 我发现currDrawInfo为null
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;
}
}
node->userData()
奇了怪了,我写的那个自定义渲染组件,竟然c++层获取不到entry,只有获取到entity,才能执行handleDrawInfo
看着像是jsb层在在设置这个userData
对应的ts层代码在这里
看到是在onLoad里面设置,我发现是我的代码中没有调用super.onLoad导致的bug