宝爷Debug小记——Cocos2d-x(3.13之前的版本)底层BUG导致Spine渲染花屏
最近在工作中碰到不少棘手的BUG,其中的一个是Spine骨骼的渲染花屏,在战斗中派发出大量士兵之后有概率出现花屏闪烁(如下图所示),这种莫名奇妙且难以重现的BUG最为蛋疼。
n)dk)%25n5h.jpg)

static int skiptype = ;
void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t transformFlags) {
SkeletonBatch* batch = SkeletonBatch::getInstance(); for (auto t : _curTriangles)
{
TrianglesMgr::getInstance()->freeTriangles(t);
}
_curTriangles.clear();
_triCmds.clear(); Color3B nodeColor = getColor();
_skeleton->r = nodeColor.r / (float);
_skeleton->g = nodeColor.g / (float);
_skeleton->b = nodeColor.b / (float);
_skeleton->a = getDisplayedOpacity() / (float); Color4F color;
AttachmentVertices* attachmentVertices = nullptr;
for (int i = , n = _skeleton->slotsCount; i < n; ++i) {
spSlot* slot = _skeleton->drawOrder[i];
if (!slot->attachment) continue;
if (slot->attachment->type == skiptype) continue;
switch (slot->attachment->type) {
case SP_ATTACHMENT_REGION: {
spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment;
spRegionAttachment_computeWorldVertices(attachment, slot->bone, _worldVertices);
attachmentVertices = getAttachmentVertices(attachment);
color.r = attachment->r;
color.g = attachment->g;
color.b = attachment->b;
color.a = attachment->a;
break;
}
case SP_ATTACHMENT_MESH: {
spMeshAttachment* attachment = (spMeshAttachment*)slot->attachment;
spMeshAttachment_computeWorldVertices(attachment, slot, _worldVertices);
attachmentVertices = getAttachmentVertices(attachment);
color.r = attachment->r;
color.g = attachment->g;
color.b = attachment->b;
color.a = attachment->a;
break;
}
default:



void Renderer::processRenderCommand(RenderCommand* command)
{
auto commandType = command->getType();
if( RenderCommand::Type::TRIANGLES_COMMAND == commandType)
{
// flush other queues
flush3D(); auto cmd = static_cast<TrianglesCommand*>(command); // flush own queue when buffer is full
if(_filledVertex + cmd->getVertexCount() > VBO_SIZE || _filledIndex + cmd->getIndexCount() > INDEX_VBO_SIZE)
{
CCASSERT(cmd->getVertexCount()>= && cmd->getVertexCount() < VBO_SIZE, "VBO for vertex is not big enough, please break the data down or use customized render command");
CCASSERT(cmd->getIndexCount()>= && cmd->getIndexCount() < INDEX_VBO_SIZE, "VBO for index is not big enough, please break the data down or use customized render command");
drawBatchedTriangles();
} // queue it
_queuedTriangleCommands.push_back(cmd);
_filledIndex += cmd->getIndexCount();
_filledVertex += cmd->getVertexCount();
}
// 增加一些调试用的静态变量
static bool __dbg = false;
static bool __deepDbg = false;
static int __cmdCount = ;
static int __curCmdCount = ;
static int __idxCount = ;
static int __vexCount = ;
static int __maxidx = ;
void Renderer::fillVerticesAndIndices(const TrianglesCommand* cmd)
{
memcpy(&_verts[_filledVertex], cmd->getVertices(), sizeof(V3F_C4B_T2F) * cmd->getVertexCount()); // fill vertex, and convert them to world coordinates
const Mat4& modelView = cmd->getModelView();
for(ssize_t i=; i < cmd->getVertexCount(); ++i)
{
modelView.transformPoint(&(_verts[i + _filledVertex].vertices));
// 打印所有顶点的xyz和纹理uv
if(__dbg && __deepDbg)
{
CCLOG("vertex %d is xyz %.2f,%.2f,%.2f uv %.2f,%.2f", i + _filledVertex - __vexCount,_verts[i + _filledVertex].vertices.x,
_verts[i + _filledVertex].vertices.y, _verts[i + _filledVertex].vertices.z,
_verts[i + _filledVertex].texCoords.u, _verts[i + _filledVertex].texCoords.v);
}
} // fill index
const unsigned short* indices = cmd->getIndices();
for(ssize_t i=; i< cmd->getIndexCount(); ++i)
{
_indices[_filledIndex + i] = _filledVertex + indices[i];
if (__dbg)
{
if (__maxidx < _indices[_filledIndex + i])
{
__maxidx = _indices[_filledIndex + i];
}
if (__deepDbg)
{
CCLOG("index %d is %d", _filledIndex + i - __idxCount, _indices[_filledIndex + i] - __vexCount);
}
}
} _filledVertex += cmd->getVertexCount();
_filledIndex += cmd->getIndexCount();
} void Renderer::drawBatchedTriangles()
{
if(_queuedTriangleCommands.empty())
return; CCGL_DEBUG_INSERT_EVENT_MARKER("RENDERER_BATCH_TRIANGLES"); if (__dbg)
{
__vexCount = ;
__idxCount = ;
__curCmdCount = ;
}
_filledVertex = ;
_filledIndex = ; /************** 1: Setup up vertices/indices *************/ _triBatchesToDraw[].offset = ;
_triBatchesToDraw[].indicesToDraw = ;
_triBatchesToDraw[].cmd = nullptr; int batchesTotal = ;
int prevMaterialID = -;
bool firstCommand = true; for(auto it = std::begin(_queuedTriangleCommands); it != std::end(_queuedTriangleCommands); ++it)
{
const auto& cmd = *it;
auto currentMaterialID = cmd->getMaterialID();
const bool batchable = !cmd->isSkipBatching();
if (__dbg)
{
if (__curCmdCount % __cmdCount == )
{
CCLOG("begin %d =====================================", __curCmdCount / __cmdCount);
__vexCount = _filledVertex;
__idxCount = _filledIndex;
}
++__curCmdCount;
}
fillVerticesAndIndices(cmd); // in the same batch ?
if (batchable && (prevMaterialID == currentMaterialID || firstCommand))
{
CC_ASSERT(firstCommand || _triBatchesToDraw[batchesTotal].cmd->getMaterialID() == cmd->getMaterialID() && "argh... error in logic");
_triBatchesToDraw[batchesTotal].indicesToDraw += cmd->getIndexCount();
_triBatchesToDraw[batchesTotal].cmd = cmd;
}
else
{
// is this the first one?
if (!firstCommand) {
batchesTotal++;
_triBatchesToDraw[batchesTotal].offset = _triBatchesToDraw[batchesTotal-].offset + _triBatchesToDraw[batchesTotal-].indicesToDraw;
} _triBatchesToDraw[batchesTotal].cmd = cmd;
_triBatchesToDraw[batchesTotal].indicesToDraw = (int) cmd->getIndexCount(); // is this a single batch ? Prevent creating a batch group then
if (!batchable)
currentMaterialID = -;
} // capacity full ?
if (batchesTotal + >= _triBatchesToDrawCapacity) {
_triBatchesToDrawCapacity *= 1.4;
_triBatchesToDraw = (TriBatchToDraw*) realloc(_triBatchesToDraw, sizeof(_triBatchesToDraw[]) * _triBatchesToDrawCapacity);
} prevMaterialID = currentMaterialID;
firstCommand = false;
}
batchesTotal++;
if (__dbg)
{
CCLOG("MAX IDX %d", __maxidx);
}
__dbg = false;
for (int i=; i<batchesTotal; ++i)
{
CC_ASSERT(_triBatchesToDraw[i].cmd && "Invalid batch");
_triBatchesToDraw[i].cmd->useMaterial();
glDrawElements(GL_TRIANGLES, (GLsizei) _triBatchesToDraw[i].indicesToDraw, GL_UNSIGNED_SHORT, (GLvoid*) (_triBatchesToDraw[i].offset*sizeof(_indices[])) );
_drawnBatches++;
_drawnVertices += _triBatchesToDraw[i].indicesToDraw;
}
宝爷Debug小记——Cocos2d-x(3.13之前的版本)底层BUG导致Spine渲染花屏的更多相关文章
- Archlinux安装指南~小米笔记本Air 13.3英寸版本
小米笔记本Air 13.3英寸版本,配置为:Intel Core i5-6200U处理器.8GB内存.256GB固态硬盘.NVIDIA GeForce 940MX独立显卡,13.3英寸1920X108 ...
- Node程序debug小记
有时候,所见并不是所得,有些包,你需要去翻他的源码才知道为什么会这样. 背景 今天调试一个程序,用到了一个很久之前的NPM包,名为formstream,用来将form表单数据转换为流的形式进行接口调用 ...
- XE7 & IOS开发之开发账号(1):开发证书、AppID、设备、开发授权profile的申请使用,附Debug真机调试演示(XCode所有版本通用,有图有真相)
网上能找到的关于Delphi XE系列的移动开发的相关文章甚少,本文尽量以详细的图文内容.傻瓜式的表达来告诉你想要的答案. 原创作品,请尊重作者劳动成果,转载请注明出处!!! 注意,以下讨论都是以&q ...
- GoldenGate针对OEM 13.1的版本发布
OGG 针对OEM(Oracle Enterprise Manager) 13.1的插件已经可以从这里下载: http://www.oracle.com/technetwork/middleware/ ...
- 解决IntelliJ IDEA 13更新FindBugs 0.9.993时JRE版本过低导致启动失败问题
今晚更新FindBugs 0.9.992(FindBugs 2)至FindBugs 0.9.993(FindBugs 3)后,按要求重启IntelliJ IDEA 13.本想看看更新后多了哪些功能,结 ...
- Archlinux配置~小米笔记本Air 13.3英寸版本
1 .zsh echo $ SHELL \\查看当前正在使用shell: pacman -S zsh zsh-syntax-highlighting git wget wget https://raw ...
- 精华阅读第 13 期 |常见的八种导致 APP 内存泄漏的问题
本期是移动开发精英俱乐部的第13期文章,都是以技术为主,所以这里就不过多的进行赘述了,我们直接看干货内容吧!本文系ITOM管理平台OneAPM整理. 实际项目中的MVVM(积木)模式–序章 导读:开篇 ...
- cocos2d 2.0和UIKit混合编程, Push CCDirector的时候出现黑屏的天坑
症状 使用cocos2d 2.0和UIKit混合编程, 有一块用cocos2d编写的小程序, 将CCDirector push到一个UINavigationController里面. 虽然事先在后台初 ...
- RUEI 13.1.1版本在OEL 5.7上的安装
准备工作 ntp的工作和同步 /sbin/chkconfig --list | grep ntpd ntpd 0:off 1:off 2:off 3:off 4:off 5:off 6:off /sb ...
随机推荐
- iOS开发之@Selector参数的传递
比如: NSMutableDictionary *dic = [[NUMutableDictionary alloc]init]; [dic setValue:@”haha” forKey:@”tes ...
- cassandra高级操作之索引、排序以及分页
本次就给大家讲讲cassandra的高级操作:索引.排序和分页:处于性能的考虑,cassandra对这些支持都比较简单,所以我们不能希望cassandra完全适用于我们的逻辑,而是应该将我们的逻辑设计 ...
- 基于CDIF实现的——API在线自动化测试
传统的测试工具在测试一个API的时候,必须手动填写这个API所需要接收的所有信息,比如一个查询航班动态的API,他接收两个输入字段,一个叫flight, 一个叫date,那么测试这个API的用户,需要 ...
- JDBC连接数据库实现删除功能
这次同样运用之前写过的部分代码进行改变,实现一个删除功能,这个功能很好添加,表单中只要form一个参数到DeleteServlet中,所以重点的代码还是在DeleteServlet中实现业务逻辑. 我 ...
- Terminating app due to uncaught exception 'NSUnknownKeyException' this class is not key value coding-compliant for the key
Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[ViewController > se ...
- selenide小白教程
目的: 趁着清明假期临近把手头工作整理了一下,前段时间老大给了一个selenide研究的任务,虽然对selenium的应用比较熟悉,但是以前一直没怎么研究过其他衍生的技术,在研究过程中发现国内好的帖子 ...
- RDCの自我介绍
........................................... 大家好,这里是RUSH_D_CAT.一只ACMer,19岁的少年,From SDU,大二. Q: 1950499 ...
- 20155232 2016-2017-3 《Java程序设计》第5周学习总结
20155232 2016-2017-3 <Java程序设计>第5周学习总结 教材学习内容总结 第八章 异常处理 1.使用try和catch 将正常的流程放try块中,异常处理放catch ...
- linux-SSR多用户版配置详解
前述:好久没有玩服务器,今天有一哥们要浏览下external website,就搭建一个新的服务器(本人用Vultr的Japan2.5$/mon centOs7.0 64位) 嗯,条件差不多了,开始啦 ...
- 老李分享:loadrunner 的86401错误
老李分享:loadrunner 的86401错误 系统和软件配置: os:windows 2003loadruner版本:LoadRunner11loadrunner:协议:SMTP协议并发数:2 ...