However, if I use your option 1, but change the glBufferSubData call in draw() to this:
context.extensions.glBufferSubData (GL_ARRAY_BUFFER, 0, (GLsizeiptr) sizeof (vertexData), vertexData);
effectively having it copy the whole buffer each time, but still only drawing the used parts (based on numVertices), the speed is still as fast as it was before. Something about calling glBufferSubData on less than the full size of the VBO is killing performance. The big question is, does my change above (in conjunction with your option 1 (>=)) fix the glitch? I still can't test that here.
That is really odd but TBH this whole hack is odd. It honestly makes no sense at all and this seems even worse. How much slower are we talking? I do not really have apps that do a whole lot of on-screen animation but on all my devices I am not seeing a slow down at all, but I do not have a Galaxy Note 4 either.
The biggest reason why your slowdown on the Note 4 makes no sense is that is normal operation to not always use the full VBO. In fact half the time JUCE is not even using the full number of potential vertices it can anyway.
Maybe run the JUCE::demo app and record the FPS before the change and after and see the difference. Curious what kind of change it reports.
Using your change and option 1 the glitch remains.
Now that is even more odd for the speed. I am wondering if copying the data up should happen on a boundary. So leaving it at 255 but stopping it early actually does 1020 vertices instead of 1024. If that was the case then option 2 would be better in.
VertexInfo vertexData[numQuads*4 + 1];