Non-integer framerate steps (45 fps) are evidence of CPU side problems. It's dropping every 4th frame. If it were an integer step ( {15, 30, 60} ) then you could say that it's consistently dropping frames and possibly a slow render call.
As BadLogic put it, "Use the profiler, Luke."
Nate's concern that for the same scene you are using more verts is a good concern. My first guess was that the number of verts being submitted in the DRAW call was the size of the buffer instead of the used count (it's not). My second guess is a really long command chain cache with bad verts.
If I were a betting man, I would probably fault this code here:
void SkeletonBatch::addCommand (cocos2d::Renderer* renderer, float globalZOrder, GLuint textureID, GLProgramState* glProgramState,
BlendFunc blendFunc, const TrianglesCommand::Triangles& triangles, const Mat4& transform, uint32_t transformFlags
) {
// We don't know what order or size we are getting attachments, or if the currently allocated verts are the right size, so...
if (_command->triangles->verts) {
free(_command->triangles->verts);
_command->triangles->verts = NULL;
}
// malloc every frame
_command->triangles->verts = (V3F_C4B_T2F *)malloc(sizeof(V3F_C4B_T2F) * triangles.vertCount);
// copy every frame
memcpy(_command->triangles->verts, triangles.verts, sizeof(V3F_C4B_T2F) * triangles.vertCount);
_command->triangles->vertCount = triangles.vertCount;
_command->triangles->indexCount = triangles.indexCount;
_command->triangles->indices = triangles.indices;
_command->trianglesCommand->init(globalZOrder, textureID, glProgramState, blendFunc, *_command->triangles, transform);
renderer->addCommand(_command->trianglesCommand);
// let's create a long command chain 'cache', although we aren't certain that every frame we will use every command
if (!_command->next) _command->next = new Command();
_command = _command->next;
}
So Cocos2dx already has an issue raised to "optimize".
Here are my suggestions, your mileage may vary.
SkeletonBatch::update
is a good place to delineate frames. To reset.
- Use a command pool and grab commands from there instead of new()ing them on the end of the chain. This means that at the end of the frame you would need to break the chain.
- use a large chunk of memory to allocate verts. Share this memory with
AttachmentVertices::_triangles->verts
and write a manager that works similar to new
but returns sections of the larger chunk. Reset() the manager's cursor to zero on SkeletonBatch::update
The biggest issue with this approach is reallocating. I'd use std::vector<V3F_C4B_T2F> for the memory pool, but you can only resize between frames. That means either dropping verts once the memory is full and resizing the next frame or having the user specify the init() batch size.